diff options
| author | Stefan Monnier | 2024-03-08 01:48:59 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2024-03-08 02:04:59 -0500 |
| commit | bd017175d4571e24ef1fdf84676136af1d36002d (patch) | |
| tree | ba1ed773d1b756446d048d1136f45f668bc38333 | |
| parent | 945af4d9d11192d262f4fabbc66ee83f5beefc86 (diff) | |
| download | emacs-bd017175d4571e24ef1fdf84676136af1d36002d.tar.gz emacs-bd017175d4571e24ef1fdf84676136af1d36002d.zip | |
Simplify type hierarchy operations
Now that built-in types have classes that describe their
relationships exactly like struct/eieio/oclosure classes,
we can the code that navigates that DAG.
* lisp/emacs-lisp/cl-generic.el (cl--generic-struct-tag): Move to
`eieio-core.el`.
(cl--generic-type-specializers): Rename from
`cl--generic-struct-specializers`. Make it work for any class.
(cl--generic-typeof-generalizer, cl--generic-oclosure-generalizer): Use it.
(cl--generic-struct-generalizer): Delete generalizer.
(cl-generic-generalizers :extra "cl-struct"): Delete method.
(prefill 0 cl--generic-generalizer): Move to after the typeof.
(cl-generic-generalizers :extra "typeof"): Rewrite to use
classes rather than `cl--all-builtin-types`.
(cl-generic--oclosure-specializers): Delete function.
* lisp/emacs-lisp/cl-preloaded.el (cl--direct-supertypes-of-type)
(cl--typeof-types, cl--all-builtin-types): Delete constants.
* lisp/emacs-lisp/comp-cstr.el (comp--typeof-builtin-types):
Delete constant.
(comp--cl-class-hierarchy): Simplify.
(comp--compute-typeof-types): Simplify now that
`comp--cl-class-hierarchy` and `comp--all-classes` work for built-in
types as well.
(comp--direct-supertypes): Just use `cl--class-parents`.
(comp-supertypes): Simplify since typeof-types should now be complete.
* lisp/emacs-lisp/eieio-core.el (eieio-defclass-autoload):
Use `superclasses` argument, so we can find parents before it's loaded.
(eieio--class-precedence-c3, eieio--class-precedence-dfs):
Don't add a `eieio-default-superclass` parent any more.
(eieio--class/struct-parents): Delete function.
(eieio--class-precedence-bfs): Use `eieio--class-parents` instead.
Don't stop when reaching `eieio-default-superclass`.
(cl--generic-struct-tag): Move from `cl-generic.el`.
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 67 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-preloaded.el | 30 | ||||
| -rw-r--r-- | lisp/emacs-lisp/comp-cstr.el | 55 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio-core.el | 51 |
4 files changed, 49 insertions, 154 deletions
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index f439a97f88c..84eb800ec24 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -1330,62 +1330,31 @@ These match if the argument is `eql' to VAL." | |||
| 1330 | (cl--generic-prefill-dispatchers (terminal-parameter nil 'xterm--set-selection) | 1330 | (cl--generic-prefill-dispatchers (terminal-parameter nil 'xterm--set-selection) |
| 1331 | (eql nil)) | 1331 | (eql nil)) |
| 1332 | 1332 | ||
| 1333 | ;;; Support for cl-defstructs specializers. | 1333 | ;;; Dispatch on "normal types". |
| 1334 | 1334 | ||
| 1335 | (defun cl--generic-struct-tag (name &rest _) | 1335 | (defun cl--generic-type-specializers (tag &rest _) |
| 1336 | ;; Use exactly the same code as for `typeof'. | ||
| 1337 | `(if ,name (type-of ,name) 'null)) | ||
| 1338 | |||
| 1339 | (defun cl--generic-struct-specializers (tag &rest _) | ||
| 1340 | (and (symbolp tag) | 1336 | (and (symbolp tag) |
| 1341 | (let ((class (get tag 'cl--class))) | 1337 | (let ((class (cl--find-class tag))) |
| 1342 | (when (cl-typep class 'cl-structure-class) | 1338 | (when class |
| 1343 | (cl--class-allparents class))))) | 1339 | (cl--class-allparents class))))) |
| 1344 | 1340 | ||
| 1345 | (cl-generic-define-generalizer cl--generic-struct-generalizer | ||
| 1346 | 50 #'cl--generic-struct-tag | ||
| 1347 | #'cl--generic-struct-specializers) | ||
| 1348 | |||
| 1349 | (cl-defmethod cl-generic-generalizers :extra "cl-struct" (type) | ||
| 1350 | "Support for dispatch on types defined by `cl-defstruct'." | ||
| 1351 | (or | ||
| 1352 | (when (symbolp type) | ||
| 1353 | ;; Use the "cl--struct-class*" (inlinable) functions/macros rather than | ||
| 1354 | ;; the "cl-struct-*" variants which aren't inlined, so that dispatch can | ||
| 1355 | ;; take place without requiring cl-lib. | ||
| 1356 | (let ((class (cl--find-class type))) | ||
| 1357 | (and (cl-typep class 'cl-structure-class) | ||
| 1358 | (or (null (cl--struct-class-type class)) | ||
| 1359 | (error "Can't dispatch on cl-struct %S: type is %S" | ||
| 1360 | type (cl--struct-class-type class))) | ||
| 1361 | (progn (cl-assert (null (cl--struct-class-named class))) t) | ||
| 1362 | (list cl--generic-struct-generalizer)))) | ||
| 1363 | (cl-call-next-method))) | ||
| 1364 | |||
| 1365 | (cl--generic-prefill-dispatchers 0 cl--generic-generalizer) | ||
| 1366 | |||
| 1367 | ;;; Dispatch on "system types". | ||
| 1368 | |||
| 1369 | (cl-generic-define-generalizer cl--generic-typeof-generalizer | 1341 | (cl-generic-define-generalizer cl--generic-typeof-generalizer |
| 1370 | ;; FIXME: We could also change `type-of' to return `null' for nil. | 1342 | ;; FIXME: We could also change `type-of' to return `null' for nil. |
| 1371 | 10 (lambda (name &rest _) `(if ,name (type-of ,name) 'null)) | 1343 | 10 (lambda (name &rest _) `(if ,name (type-of ,name) 'null)) |
| 1372 | (lambda (tag &rest _) | 1344 | #'cl--generic-type-specializers) |
| 1373 | (and (symbolp tag) (assq tag cl--typeof-types)))) | ||
| 1374 | 1345 | ||
| 1375 | (cl-defmethod cl-generic-generalizers :extra "typeof" (type) | 1346 | (cl-defmethod cl-generic-generalizers :extra "typeof" (type) |
| 1376 | "Support for dispatch on builtin types. | 1347 | "Support for dispatch on types. |
| 1377 | See the full list and their hierarchy in `cl--typeof-types'." | 1348 | This currently works for built-in types and types built on top of records." |
| 1378 | ;; FIXME: Add support for other types accepted by `cl-typep' such | 1349 | ;; FIXME: Add support for other types accepted by `cl-typep' such |
| 1379 | ;; as `character', `face', `function', ... | 1350 | ;; as `character', `face', `function', ... |
| 1380 | (or | 1351 | (or |
| 1381 | (and (memq type cl--all-builtin-types) | 1352 | (and (symbolp type) |
| 1382 | (progn | 1353 | (not (eq type t)) ;; Handled by the `t-generalizer'. |
| 1383 | ;; FIXME: While this wrinkle in the semantics can be occasionally | 1354 | (let ((class (cl--find-class type))) |
| 1384 | ;; problematic, this warning is more often annoying than helpful. | 1355 | (memq (type-of class) |
| 1385 | ;;(if (memq type '(vector array sequence)) | 1356 | '(built-in-class cl-structure-class eieio--class))) |
| 1386 | ;; (message "`%S' also matches CL structs and EIEIO classes" | 1357 | (list cl--generic-typeof-generalizer)) |
| 1387 | ;; type)) | ||
| 1388 | (list cl--generic-typeof-generalizer))) | ||
| 1389 | (cl-call-next-method))) | 1358 | (cl-call-next-method))) |
| 1390 | 1359 | ||
| 1391 | (cl--generic-prefill-dispatchers 0 integer) | 1360 | (cl--generic-prefill-dispatchers 0 integer) |
| @@ -1393,6 +1362,8 @@ See the full list and their hierarchy in `cl--typeof-types'." | |||
| 1393 | (cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer) | 1362 | (cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer) |
| 1394 | (cl--generic-prefill-dispatchers 0 (eql 'x) integer) | 1363 | (cl--generic-prefill-dispatchers 0 (eql 'x) integer) |
| 1395 | 1364 | ||
| 1365 | (cl--generic-prefill-dispatchers 0 cl--generic-generalizer) | ||
| 1366 | |||
| 1396 | ;;; Dispatch on major mode. | 1367 | ;;; Dispatch on major mode. |
| 1397 | 1368 | ||
| 1398 | ;; Two parts: | 1369 | ;; Two parts: |
| @@ -1430,19 +1401,13 @@ Used internally for the (major-mode MODE) context specializers." | |||
| 1430 | (defun cl--generic-oclosure-tag (name &rest _) | 1401 | (defun cl--generic-oclosure-tag (name &rest _) |
| 1431 | `(oclosure-type ,name)) | 1402 | `(oclosure-type ,name)) |
| 1432 | 1403 | ||
| 1433 | (defun cl-generic--oclosure-specializers (tag &rest _) | ||
| 1434 | (and (symbolp tag) | ||
| 1435 | (let ((class (cl--find-class tag))) | ||
| 1436 | (when (cl-typep class 'oclosure--class) | ||
| 1437 | (oclosure--class-allparents class))))) | ||
| 1438 | |||
| 1439 | (cl-generic-define-generalizer cl--generic-oclosure-generalizer | 1404 | (cl-generic-define-generalizer cl--generic-oclosure-generalizer |
| 1440 | ;; Give slightly higher priority than the struct specializer, so that | 1405 | ;; Give slightly higher priority than the struct specializer, so that |
| 1441 | ;; for a generic function with methods dispatching structs and on OClosures, | 1406 | ;; for a generic function with methods dispatching structs and on OClosures, |
| 1442 | ;; we first try `oclosure-type' before `type-of' since `type-of' will return | 1407 | ;; we first try `oclosure-type' before `type-of' since `type-of' will return |
| 1443 | ;; non-nil for an OClosure as well. | 1408 | ;; non-nil for an OClosure as well. |
| 1444 | 51 #'cl--generic-oclosure-tag | 1409 | 51 #'cl--generic-oclosure-tag |
| 1445 | #'cl-generic--oclosure-specializers) | 1410 | #'cl--generic-type-specializers) |
| 1446 | 1411 | ||
| 1447 | (cl-defmethod cl-generic-generalizers :extra "oclosure-struct" (type) | 1412 | (cl-defmethod cl-generic-generalizers :extra "oclosure-struct" (type) |
| 1448 | "Support for dispatch on types defined by `oclosure-define'." | 1413 | "Support for dispatch on types defined by `oclosure-define'." |
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el index 1b330e7f761..5743684fa89 100644 --- a/lisp/emacs-lisp/cl-preloaded.el +++ b/lisp/emacs-lisp/cl-preloaded.el | |||
| @@ -433,36 +433,6 @@ For this build of Emacs it's %dbit." | |||
| 433 | (setf (cl--class-parents (cl--find-class 'cl-structure-object)) | 433 | (setf (cl--class-parents (cl--find-class 'cl-structure-object)) |
| 434 | (list (cl--find-class 'record)))) | 434 | (list (cl--find-class 'record)))) |
| 435 | 435 | ||
| 436 | (defconst cl--direct-supertypes-of-type | ||
| 437 | ;; Please run `sycdoc-update-type-hierarchy' in | ||
| 438 | ;; `admin/syncdoc-type-hierarchy.el' each time this is modified to | ||
| 439 | ;; reflect the change in the documentation. | ||
| 440 | (let ((table (make-hash-table :test #'eq))) | ||
| 441 | (mapatoms | ||
| 442 | (lambda (type) | ||
| 443 | (let ((class (get type 'cl--class))) | ||
| 444 | (when (built-in-class-p class) | ||
| 445 | (puthash type (mapcar #'cl--class-name (cl--class-parents class)) | ||
| 446 | table))))) | ||
| 447 | table) | ||
| 448 | "Hash table TYPE -> SUPERTYPES.") | ||
| 449 | |||
| 450 | (defconst cl--typeof-types | ||
| 451 | (letrec ((alist nil)) | ||
| 452 | (maphash (lambda (type _) | ||
| 453 | (let ((class (get type 'cl--class))) | ||
| 454 | ;; FIXME: Can't remember why `t' is excluded. | ||
| 455 | (push (remq t (cl--class-allparents class)) alist))) | ||
| 456 | cl--direct-supertypes-of-type) | ||
| 457 | alist) | ||
| 458 | "Alist of supertypes. | ||
| 459 | Each element has the form (TYPE . SUPERTYPES) where TYPE is one of | ||
| 460 | the symbols returned by `type-of', and SUPERTYPES is the list of its | ||
| 461 | supertypes from the most specific to least specific.") | ||
| 462 | |||
| 463 | (defconst cl--all-builtin-types | ||
| 464 | (delete-dups (copy-sequence (apply #'append cl--typeof-types)))) | ||
| 465 | |||
| 466 | ;; Make sure functions defined with cl-defsubst can be inlined even in | 436 | ;; Make sure functions defined with cl-defsubst can be inlined even in |
| 467 | ;; packages which do not require CL. We don't put an autoload cookie | 437 | ;; packages which do not require CL. We don't put an autoload cookie |
| 468 | ;; directly on that function, since those cookies only go to cl-loaddefs. | 438 | ;; directly on that function, since those cookies only go to cl-loaddefs. |
diff --git a/lisp/emacs-lisp/comp-cstr.el b/lisp/emacs-lisp/comp-cstr.el index 1c6acaa6385..5922a8caf12 100644 --- a/lisp/emacs-lisp/comp-cstr.el +++ b/lisp/emacs-lisp/comp-cstr.el | |||
| @@ -38,12 +38,6 @@ | |||
| 38 | (require 'cl-lib) | 38 | (require 'cl-lib) |
| 39 | (require 'cl-extra) ;HACK: For `cl-find-class' when `cl-loaddefs' is missing. | 39 | (require 'cl-extra) ;HACK: For `cl-find-class' when `cl-loaddefs' is missing. |
| 40 | 40 | ||
| 41 | (defconst comp--typeof-builtin-types (mapcar (lambda (x) | ||
| 42 | (append x '(t))) | ||
| 43 | cl--typeof-types) | ||
| 44 | ;; TODO can we just add t in `cl--typeof-types'? | ||
| 45 | "Like `cl--typeof-types' but with t as common supertype.") | ||
| 46 | |||
| 47 | (cl-defstruct (comp-cstr (:constructor comp--type-to-cstr | 41 | (cl-defstruct (comp-cstr (:constructor comp--type-to-cstr |
| 48 | (type &aux | 42 | (type &aux |
| 49 | (null (eq type 'null)) | 43 | (null (eq type 'null)) |
| @@ -89,15 +83,7 @@ Integer values are handled in the `range' slot.") | |||
| 89 | 83 | ||
| 90 | (defun comp--cl-class-hierarchy (x) | 84 | (defun comp--cl-class-hierarchy (x) |
| 91 | "Given a class name `x' return its hierarchy." | 85 | "Given a class name `x' return its hierarchy." |
| 92 | (let ((parents (cl--class-allparents (cl--struct-get-class x)))) | 86 | (cl--class-allparents (cl--find-class x))) |
| 93 | (if (memq t parents) | ||
| 94 | parents | ||
| 95 | `(,@parents | ||
| 96 | ;; FIXME: AFAICT, `comp--all-classes' will also find those struct types | ||
| 97 | ;; which use :type and can thus be either `vector' or `cons' (the latter | ||
| 98 | ;; isn't `atom'). | ||
| 99 | atom | ||
| 100 | t)))) | ||
| 101 | 87 | ||
| 102 | (defun comp--all-classes () | 88 | (defun comp--all-classes () |
| 103 | "Return all non built-in type names currently defined." | 89 | "Return all non built-in type names currently defined." |
| @@ -109,8 +95,7 @@ Integer values are handled in the `range' slot.") | |||
| 109 | res)) | 95 | res)) |
| 110 | 96 | ||
| 111 | (defun comp--compute-typeof-types () | 97 | (defun comp--compute-typeof-types () |
| 112 | (append comp--typeof-builtin-types | 98 | (mapcar #'comp--cl-class-hierarchy (comp--all-classes))) |
| 113 | (mapcar #'comp--cl-class-hierarchy (comp--all-classes)))) | ||
| 114 | 99 | ||
| 115 | (defun comp--compute--pred-type-h () | 100 | (defun comp--compute--pred-type-h () |
| 116 | (cl-loop with h = (make-hash-table :test #'eq) | 101 | (cl-loop with h = (make-hash-table :test #'eq) |
| @@ -275,19 +260,10 @@ Return them as multiple value." | |||
| 275 | (symbol-name y))) | 260 | (symbol-name y))) |
| 276 | 261 | ||
| 277 | (defun comp--direct-supertypes (type) | 262 | (defun comp--direct-supertypes (type) |
| 278 | (or | 263 | (when (symbolp type) ;; FIXME: Can this test ever fail? |
| 279 | (gethash type cl--direct-supertypes-of-type) | 264 | (let* ((class (cl--find-class type)) |
| 280 | (let ((supers (comp-supertypes type))) | 265 | (parents (if class (cl--class-parents class)))) |
| 281 | (cl-assert (eq type (car supers))) | 266 | (mapcar #'cl--class-name parents)))) |
| 282 | (cl-loop | ||
| 283 | with notdirect = nil | ||
| 284 | with direct = nil | ||
| 285 | for parent in (cdr supers) | ||
| 286 | unless (memq parent notdirect) | ||
| 287 | do (progn | ||
| 288 | (push parent direct) | ||
| 289 | (setq notdirect (append notdirect (comp-supertypes parent)))) | ||
| 290 | finally return direct)))) | ||
| 291 | 267 | ||
| 292 | (defsubst comp-subtype-p (type1 type2) | 268 | (defsubst comp-subtype-p (type1 type2) |
| 293 | "Return t if TYPE1 is a subtype of TYPE2 or nil otherwise." | 269 | "Return t if TYPE1 is a subtype of TYPE2 or nil otherwise." |
| @@ -359,23 +335,8 @@ Return them as multiple value." | |||
| 359 | 335 | ||
| 360 | (defun comp-supertypes (type) | 336 | (defun comp-supertypes (type) |
| 361 | "Return the ordered list of supertypes of TYPE." | 337 | "Return the ordered list of supertypes of TYPE." |
| 362 | ;; FIXME: We should probably keep the results in | 338 | (or (assq type (comp-cstr-ctxt-typeof-types comp-ctxt)) |
| 363 | ;; `comp-cstr-ctxt-typeof-types' (or maybe even precompute them | 339 | (error "Type %S missing from typeof-types!" type))) |
| 364 | ;; and maybe turn `comp-cstr-ctxt-typeof-types' into a hash-table). | ||
| 365 | ;; Or maybe we shouldn't keep structs and defclasses in it, | ||
| 366 | ;; and just use `cl--class-allparents' when needed (and refuse to | ||
| 367 | ;; compute their direct subtypes since we can't know them). | ||
| 368 | (cl-loop | ||
| 369 | named loop | ||
| 370 | with above | ||
| 371 | for lane in (comp-cstr-ctxt-typeof-types comp-ctxt) | ||
| 372 | do (let ((x (memq type lane))) | ||
| 373 | (cond | ||
| 374 | ((null x) nil) | ||
| 375 | ((eq x lane) (cl-return-from loop x)) ;A base type: easy case. | ||
| 376 | (t (setq above | ||
| 377 | (if above (comp--intersection x above) x))))) | ||
| 378 | finally return above)) | ||
| 379 | 340 | ||
| 380 | (defun comp-union-typesets (&rest typesets) | 341 | (defun comp-union-typesets (&rest typesets) |
| 381 | "Union types present into TYPESETS." | 342 | "Union types present into TYPESETS." |
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el index 9945e19c65c..5418f53be35 100644 --- a/lisp/emacs-lisp/eieio-core.el +++ b/lisp/emacs-lisp/eieio-core.el | |||
| @@ -191,7 +191,7 @@ Abstract classes cannot be instantiated." | |||
| 191 | 191 | ||
| 192 | ;; We autoload this because it's used in `make-autoload'. | 192 | ;; We autoload this because it's used in `make-autoload'. |
| 193 | ;;;###autoload | 193 | ;;;###autoload |
| 194 | (defun eieio-defclass-autoload (cname _superclasses filename doc) | 194 | (defun eieio-defclass-autoload (cname superclasses filename doc) |
| 195 | "Create autoload symbols for the EIEIO class CNAME. | 195 | "Create autoload symbols for the EIEIO class CNAME. |
| 196 | SUPERCLASSES are the superclasses that CNAME inherits from. | 196 | SUPERCLASSES are the superclasses that CNAME inherits from. |
| 197 | DOC is the docstring for CNAME. | 197 | DOC is the docstring for CNAME. |
| @@ -199,15 +199,9 @@ This function creates a mock-class for CNAME and adds it into | |||
| 199 | SUPERCLASSES as children. | 199 | SUPERCLASSES as children. |
| 200 | It creates an autoload function for CNAME's constructor." | 200 | It creates an autoload function for CNAME's constructor." |
| 201 | ;; Assume we've already debugged inputs. | 201 | ;; Assume we've already debugged inputs. |
| 202 | |||
| 203 | ;; We used to store the list of superclasses in the `parent' slot (as a list | ||
| 204 | ;; of class names). But now this slot holds a list of class objects, and | ||
| 205 | ;; those parents may not exist yet, so the corresponding class objects may | ||
| 206 | ;; simply not exist yet. So instead we just don't store the list of parents | ||
| 207 | ;; here in eieio-defclass-autoload at all, since it seems that they're just | ||
| 208 | ;; not needed before the class is actually loaded. | ||
| 209 | (let* ((oldc (cl--find-class cname)) | 202 | (let* ((oldc (cl--find-class cname)) |
| 210 | (newc (eieio--class-make cname))) | 203 | (newc (eieio--class-make cname)) |
| 204 | (parents (mapcar #'cl-find-class superclasses))) | ||
| 211 | (if (eieio--class-p oldc) | 205 | (if (eieio--class-p oldc) |
| 212 | nil ;; Do nothing if we already have this class. | 206 | nil ;; Do nothing if we already have this class. |
| 213 | 207 | ||
| @@ -218,6 +212,12 @@ It creates an autoload function for CNAME's constructor." | |||
| 218 | use '%s or turn off `eieio-backward-compatibility' instead" cname) | 212 | use '%s or turn off `eieio-backward-compatibility' instead" cname) |
| 219 | "25.1")) | 213 | "25.1")) |
| 220 | 214 | ||
| 215 | (when (memq nil parents) | ||
| 216 | ;; If some parents aren't yet fully defined, just ignore them for now. | ||
| 217 | (setq parents (delq nil parents))) | ||
| 218 | (unless parents | ||
| 219 | (setq parents (list (cl--find-class 'eieio-default-superclass)))) | ||
| 220 | (setf (cl--class-parents newc) parents) | ||
| 221 | (setf (cl--find-class cname) newc) | 221 | (setf (cl--find-class cname) newc) |
| 222 | 222 | ||
| 223 | ;; Create an autoload on top of our constructor function. | 223 | ;; Create an autoload on top of our constructor function. |
| @@ -958,19 +958,13 @@ need be... May remove that later...)" | |||
| 958 | (cdr tuple) | 958 | (cdr tuple) |
| 959 | nil))) | 959 | nil))) |
| 960 | 960 | ||
| 961 | (defsubst eieio--class/struct-parents (class) | ||
| 962 | (or (eieio--class-parents class) | ||
| 963 | `(,eieio-default-superclass))) | ||
| 964 | |||
| 965 | (defun eieio--class-precedence-c3 (class) | 961 | (defun eieio--class-precedence-c3 (class) |
| 966 | "Return all parents of CLASS in c3 order." | 962 | "Return all parents of CLASS in c3 order." |
| 967 | (let ((parents (eieio--class-parents class))) | 963 | (let ((parents (eieio--class-parents class))) |
| 968 | (cons class | 964 | (cons class |
| 969 | (merge-ordered-lists | 965 | (merge-ordered-lists |
| 970 | (append | 966 | (append |
| 971 | (or | 967 | (mapcar #'eieio--class-precedence-c3 parents) |
| 972 | (mapcar #'eieio--class-precedence-c3 parents) | ||
| 973 | `((,eieio-default-superclass))) | ||
| 974 | (list parents)) | 968 | (list parents)) |
| 975 | (lambda (remaining-inputs) | 969 | (lambda (remaining-inputs) |
| 976 | (signal 'inconsistent-class-hierarchy | 970 | (signal 'inconsistent-class-hierarchy |
| @@ -984,13 +978,11 @@ need be... May remove that later...)" | |||
| 984 | (classes (copy-sequence | 978 | (classes (copy-sequence |
| 985 | (apply #'append | 979 | (apply #'append |
| 986 | (list class) | 980 | (list class) |
| 987 | (or | 981 | (mapcar |
| 988 | (mapcar | 982 | (lambda (parent) |
| 989 | (lambda (parent) | 983 | (cons parent |
| 990 | (cons parent | 984 | (eieio--class-precedence-dfs parent))) |
| 991 | (eieio--class-precedence-dfs parent))) | 985 | parents)))) |
| 992 | parents) | ||
| 993 | `((,eieio-default-superclass)))))) | ||
| 994 | (tail classes)) | 986 | (tail classes)) |
| 995 | ;; Remove duplicates. | 987 | ;; Remove duplicates. |
| 996 | (while tail | 988 | (while tail |
| @@ -1003,13 +995,12 @@ need be... May remove that later...)" | |||
| 1003 | (defun eieio--class-precedence-bfs (class) | 995 | (defun eieio--class-precedence-bfs (class) |
| 1004 | "Return all parents of CLASS in breadth-first order." | 996 | "Return all parents of CLASS in breadth-first order." |
| 1005 | (let* ((result) | 997 | (let* ((result) |
| 1006 | (queue (eieio--class/struct-parents class))) | 998 | (queue (eieio--class-parents class))) |
| 1007 | (while queue | 999 | (while queue |
| 1008 | (let ((head (pop queue))) | 1000 | (let ((head (pop queue))) |
| 1009 | (unless (member head result) | 1001 | (unless (member head result) |
| 1010 | (push head result) | 1002 | (push head result) |
| 1011 | (unless (eq head eieio-default-superclass) | 1003 | (setq queue (append queue (eieio--class-parents head)))))) |
| 1012 | (setq queue (append queue (eieio--class/struct-parents head))))))) | ||
| 1013 | (cons class (nreverse result))) | 1004 | (cons class (nreverse result))) |
| 1014 | ) | 1005 | ) |
| 1015 | 1006 | ||
| @@ -1049,6 +1040,14 @@ method invocation orders of the involved classes." | |||
| 1049 | 1040 | ||
| 1050 | ;;;; General support to dispatch based on the type of the argument. | 1041 | ;;;; General support to dispatch based on the type of the argument. |
| 1051 | 1042 | ||
| 1043 | ;; FIXME: We could almost use the typeof-generalizer (i.e. the same as | ||
| 1044 | ;; used for cl-structs), except that that generalizer doesn't support | ||
| 1045 | ;; `:method-invocation-order' :-( | ||
| 1046 | |||
| 1047 | (defun cl--generic-struct-tag (name &rest _) | ||
| 1048 | ;; Use exactly the same code as for `typeof'. | ||
| 1049 | `(if ,name (type-of ,name) 'null)) | ||
| 1050 | |||
| 1052 | (cl-generic-define-generalizer eieio--generic-generalizer | 1051 | (cl-generic-define-generalizer eieio--generic-generalizer |
| 1053 | ;; Use the exact same tagcode as for cl-struct, so that methods | 1052 | ;; Use the exact same tagcode as for cl-struct, so that methods |
| 1054 | ;; that dispatch on both kinds of objects get to share this | 1053 | ;; that dispatch on both kinds of objects get to share this |