mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
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`.
This commit is contained in:
parent
945af4d9d1
commit
bd017175d4
4 changed files with 49 additions and 154 deletions
|
|
@ -1330,62 +1330,31 @@ These match if the argument is `eql' to VAL."
|
||||||
(cl--generic-prefill-dispatchers (terminal-parameter nil 'xterm--set-selection)
|
(cl--generic-prefill-dispatchers (terminal-parameter nil 'xterm--set-selection)
|
||||||
(eql nil))
|
(eql nil))
|
||||||
|
|
||||||
;;; Support for cl-defstructs specializers.
|
;;; Dispatch on "normal types".
|
||||||
|
|
||||||
(defun cl--generic-struct-tag (name &rest _)
|
(defun cl--generic-type-specializers (tag &rest _)
|
||||||
;; Use exactly the same code as for `typeof'.
|
|
||||||
`(if ,name (type-of ,name) 'null))
|
|
||||||
|
|
||||||
(defun cl--generic-struct-specializers (tag &rest _)
|
|
||||||
(and (symbolp tag)
|
(and (symbolp tag)
|
||||||
(let ((class (get tag 'cl--class)))
|
(let ((class (cl--find-class tag)))
|
||||||
(when (cl-typep class 'cl-structure-class)
|
(when class
|
||||||
(cl--class-allparents class)))))
|
(cl--class-allparents class)))))
|
||||||
|
|
||||||
(cl-generic-define-generalizer cl--generic-struct-generalizer
|
|
||||||
50 #'cl--generic-struct-tag
|
|
||||||
#'cl--generic-struct-specializers)
|
|
||||||
|
|
||||||
(cl-defmethod cl-generic-generalizers :extra "cl-struct" (type)
|
|
||||||
"Support for dispatch on types defined by `cl-defstruct'."
|
|
||||||
(or
|
|
||||||
(when (symbolp type)
|
|
||||||
;; Use the "cl--struct-class*" (inlinable) functions/macros rather than
|
|
||||||
;; the "cl-struct-*" variants which aren't inlined, so that dispatch can
|
|
||||||
;; take place without requiring cl-lib.
|
|
||||||
(let ((class (cl--find-class type)))
|
|
||||||
(and (cl-typep class 'cl-structure-class)
|
|
||||||
(or (null (cl--struct-class-type class))
|
|
||||||
(error "Can't dispatch on cl-struct %S: type is %S"
|
|
||||||
type (cl--struct-class-type class)))
|
|
||||||
(progn (cl-assert (null (cl--struct-class-named class))) t)
|
|
||||||
(list cl--generic-struct-generalizer))))
|
|
||||||
(cl-call-next-method)))
|
|
||||||
|
|
||||||
(cl--generic-prefill-dispatchers 0 cl--generic-generalizer)
|
|
||||||
|
|
||||||
;;; Dispatch on "system types".
|
|
||||||
|
|
||||||
(cl-generic-define-generalizer cl--generic-typeof-generalizer
|
(cl-generic-define-generalizer cl--generic-typeof-generalizer
|
||||||
;; FIXME: We could also change `type-of' to return `null' for nil.
|
;; FIXME: We could also change `type-of' to return `null' for nil.
|
||||||
10 (lambda (name &rest _) `(if ,name (type-of ,name) 'null))
|
10 (lambda (name &rest _) `(if ,name (type-of ,name) 'null))
|
||||||
(lambda (tag &rest _)
|
#'cl--generic-type-specializers)
|
||||||
(and (symbolp tag) (assq tag cl--typeof-types))))
|
|
||||||
|
|
||||||
(cl-defmethod cl-generic-generalizers :extra "typeof" (type)
|
(cl-defmethod cl-generic-generalizers :extra "typeof" (type)
|
||||||
"Support for dispatch on builtin types.
|
"Support for dispatch on types.
|
||||||
See the full list and their hierarchy in `cl--typeof-types'."
|
This currently works for built-in types and types built on top of records."
|
||||||
;; FIXME: Add support for other types accepted by `cl-typep' such
|
;; FIXME: Add support for other types accepted by `cl-typep' such
|
||||||
;; as `character', `face', `function', ...
|
;; as `character', `face', `function', ...
|
||||||
(or
|
(or
|
||||||
(and (memq type cl--all-builtin-types)
|
(and (symbolp type)
|
||||||
(progn
|
(not (eq type t)) ;; Handled by the `t-generalizer'.
|
||||||
;; FIXME: While this wrinkle in the semantics can be occasionally
|
(let ((class (cl--find-class type)))
|
||||||
;; problematic, this warning is more often annoying than helpful.
|
(memq (type-of class)
|
||||||
;;(if (memq type '(vector array sequence))
|
'(built-in-class cl-structure-class eieio--class)))
|
||||||
;; (message "`%S' also matches CL structs and EIEIO classes"
|
(list cl--generic-typeof-generalizer))
|
||||||
;; type))
|
|
||||||
(list cl--generic-typeof-generalizer)))
|
|
||||||
(cl-call-next-method)))
|
(cl-call-next-method)))
|
||||||
|
|
||||||
(cl--generic-prefill-dispatchers 0 integer)
|
(cl--generic-prefill-dispatchers 0 integer)
|
||||||
|
|
@ -1393,6 +1362,8 @@ See the full list and their hierarchy in `cl--typeof-types'."
|
||||||
(cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer)
|
(cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer)
|
||||||
(cl--generic-prefill-dispatchers 0 (eql 'x) integer)
|
(cl--generic-prefill-dispatchers 0 (eql 'x) integer)
|
||||||
|
|
||||||
|
(cl--generic-prefill-dispatchers 0 cl--generic-generalizer)
|
||||||
|
|
||||||
;;; Dispatch on major mode.
|
;;; Dispatch on major mode.
|
||||||
|
|
||||||
;; Two parts:
|
;; Two parts:
|
||||||
|
|
@ -1430,19 +1401,13 @@ Used internally for the (major-mode MODE) context specializers."
|
||||||
(defun cl--generic-oclosure-tag (name &rest _)
|
(defun cl--generic-oclosure-tag (name &rest _)
|
||||||
`(oclosure-type ,name))
|
`(oclosure-type ,name))
|
||||||
|
|
||||||
(defun cl-generic--oclosure-specializers (tag &rest _)
|
|
||||||
(and (symbolp tag)
|
|
||||||
(let ((class (cl--find-class tag)))
|
|
||||||
(when (cl-typep class 'oclosure--class)
|
|
||||||
(oclosure--class-allparents class)))))
|
|
||||||
|
|
||||||
(cl-generic-define-generalizer cl--generic-oclosure-generalizer
|
(cl-generic-define-generalizer cl--generic-oclosure-generalizer
|
||||||
;; Give slightly higher priority than the struct specializer, so that
|
;; Give slightly higher priority than the struct specializer, so that
|
||||||
;; for a generic function with methods dispatching structs and on OClosures,
|
;; for a generic function with methods dispatching structs and on OClosures,
|
||||||
;; we first try `oclosure-type' before `type-of' since `type-of' will return
|
;; we first try `oclosure-type' before `type-of' since `type-of' will return
|
||||||
;; non-nil for an OClosure as well.
|
;; non-nil for an OClosure as well.
|
||||||
51 #'cl--generic-oclosure-tag
|
51 #'cl--generic-oclosure-tag
|
||||||
#'cl-generic--oclosure-specializers)
|
#'cl--generic-type-specializers)
|
||||||
|
|
||||||
(cl-defmethod cl-generic-generalizers :extra "oclosure-struct" (type)
|
(cl-defmethod cl-generic-generalizers :extra "oclosure-struct" (type)
|
||||||
"Support for dispatch on types defined by `oclosure-define'."
|
"Support for dispatch on types defined by `oclosure-define'."
|
||||||
|
|
|
||||||
|
|
@ -433,36 +433,6 @@ For this build of Emacs it's %dbit."
|
||||||
(setf (cl--class-parents (cl--find-class 'cl-structure-object))
|
(setf (cl--class-parents (cl--find-class 'cl-structure-object))
|
||||||
(list (cl--find-class 'record))))
|
(list (cl--find-class 'record))))
|
||||||
|
|
||||||
(defconst cl--direct-supertypes-of-type
|
|
||||||
;; Please run `sycdoc-update-type-hierarchy' in
|
|
||||||
;; `admin/syncdoc-type-hierarchy.el' each time this is modified to
|
|
||||||
;; reflect the change in the documentation.
|
|
||||||
(let ((table (make-hash-table :test #'eq)))
|
|
||||||
(mapatoms
|
|
||||||
(lambda (type)
|
|
||||||
(let ((class (get type 'cl--class)))
|
|
||||||
(when (built-in-class-p class)
|
|
||||||
(puthash type (mapcar #'cl--class-name (cl--class-parents class))
|
|
||||||
table)))))
|
|
||||||
table)
|
|
||||||
"Hash table TYPE -> SUPERTYPES.")
|
|
||||||
|
|
||||||
(defconst cl--typeof-types
|
|
||||||
(letrec ((alist nil))
|
|
||||||
(maphash (lambda (type _)
|
|
||||||
(let ((class (get type 'cl--class)))
|
|
||||||
;; FIXME: Can't remember why `t' is excluded.
|
|
||||||
(push (remq t (cl--class-allparents class)) alist)))
|
|
||||||
cl--direct-supertypes-of-type)
|
|
||||||
alist)
|
|
||||||
"Alist of supertypes.
|
|
||||||
Each element has the form (TYPE . SUPERTYPES) where TYPE is one of
|
|
||||||
the symbols returned by `type-of', and SUPERTYPES is the list of its
|
|
||||||
supertypes from the most specific to least specific.")
|
|
||||||
|
|
||||||
(defconst cl--all-builtin-types
|
|
||||||
(delete-dups (copy-sequence (apply #'append cl--typeof-types))))
|
|
||||||
|
|
||||||
;; Make sure functions defined with cl-defsubst can be inlined even in
|
;; Make sure functions defined with cl-defsubst can be inlined even in
|
||||||
;; packages which do not require CL. We don't put an autoload cookie
|
;; packages which do not require CL. We don't put an autoload cookie
|
||||||
;; directly on that function, since those cookies only go to cl-loaddefs.
|
;; directly on that function, since those cookies only go to cl-loaddefs.
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,6 @@
|
||||||
(require 'cl-lib)
|
(require 'cl-lib)
|
||||||
(require 'cl-extra) ;HACK: For `cl-find-class' when `cl-loaddefs' is missing.
|
(require 'cl-extra) ;HACK: For `cl-find-class' when `cl-loaddefs' is missing.
|
||||||
|
|
||||||
(defconst comp--typeof-builtin-types (mapcar (lambda (x)
|
|
||||||
(append x '(t)))
|
|
||||||
cl--typeof-types)
|
|
||||||
;; TODO can we just add t in `cl--typeof-types'?
|
|
||||||
"Like `cl--typeof-types' but with t as common supertype.")
|
|
||||||
|
|
||||||
(cl-defstruct (comp-cstr (:constructor comp--type-to-cstr
|
(cl-defstruct (comp-cstr (:constructor comp--type-to-cstr
|
||||||
(type &aux
|
(type &aux
|
||||||
(null (eq type 'null))
|
(null (eq type 'null))
|
||||||
|
|
@ -89,15 +83,7 @@ Integer values are handled in the `range' slot.")
|
||||||
|
|
||||||
(defun comp--cl-class-hierarchy (x)
|
(defun comp--cl-class-hierarchy (x)
|
||||||
"Given a class name `x' return its hierarchy."
|
"Given a class name `x' return its hierarchy."
|
||||||
(let ((parents (cl--class-allparents (cl--struct-get-class x))))
|
(cl--class-allparents (cl--find-class x)))
|
||||||
(if (memq t parents)
|
|
||||||
parents
|
|
||||||
`(,@parents
|
|
||||||
;; FIXME: AFAICT, `comp--all-classes' will also find those struct types
|
|
||||||
;; which use :type and can thus be either `vector' or `cons' (the latter
|
|
||||||
;; isn't `atom').
|
|
||||||
atom
|
|
||||||
t))))
|
|
||||||
|
|
||||||
(defun comp--all-classes ()
|
(defun comp--all-classes ()
|
||||||
"Return all non built-in type names currently defined."
|
"Return all non built-in type names currently defined."
|
||||||
|
|
@ -109,8 +95,7 @@ Integer values are handled in the `range' slot.")
|
||||||
res))
|
res))
|
||||||
|
|
||||||
(defun comp--compute-typeof-types ()
|
(defun comp--compute-typeof-types ()
|
||||||
(append comp--typeof-builtin-types
|
(mapcar #'comp--cl-class-hierarchy (comp--all-classes)))
|
||||||
(mapcar #'comp--cl-class-hierarchy (comp--all-classes))))
|
|
||||||
|
|
||||||
(defun comp--compute--pred-type-h ()
|
(defun comp--compute--pred-type-h ()
|
||||||
(cl-loop with h = (make-hash-table :test #'eq)
|
(cl-loop with h = (make-hash-table :test #'eq)
|
||||||
|
|
@ -275,19 +260,10 @@ Return them as multiple value."
|
||||||
(symbol-name y)))
|
(symbol-name y)))
|
||||||
|
|
||||||
(defun comp--direct-supertypes (type)
|
(defun comp--direct-supertypes (type)
|
||||||
(or
|
(when (symbolp type) ;; FIXME: Can this test ever fail?
|
||||||
(gethash type cl--direct-supertypes-of-type)
|
(let* ((class (cl--find-class type))
|
||||||
(let ((supers (comp-supertypes type)))
|
(parents (if class (cl--class-parents class))))
|
||||||
(cl-assert (eq type (car supers)))
|
(mapcar #'cl--class-name parents))))
|
||||||
(cl-loop
|
|
||||||
with notdirect = nil
|
|
||||||
with direct = nil
|
|
||||||
for parent in (cdr supers)
|
|
||||||
unless (memq parent notdirect)
|
|
||||||
do (progn
|
|
||||||
(push parent direct)
|
|
||||||
(setq notdirect (append notdirect (comp-supertypes parent))))
|
|
||||||
finally return direct))))
|
|
||||||
|
|
||||||
(defsubst comp-subtype-p (type1 type2)
|
(defsubst comp-subtype-p (type1 type2)
|
||||||
"Return t if TYPE1 is a subtype of TYPE2 or nil otherwise."
|
"Return t if TYPE1 is a subtype of TYPE2 or nil otherwise."
|
||||||
|
|
@ -359,23 +335,8 @@ Return them as multiple value."
|
||||||
|
|
||||||
(defun comp-supertypes (type)
|
(defun comp-supertypes (type)
|
||||||
"Return the ordered list of supertypes of TYPE."
|
"Return the ordered list of supertypes of TYPE."
|
||||||
;; FIXME: We should probably keep the results in
|
(or (assq type (comp-cstr-ctxt-typeof-types comp-ctxt))
|
||||||
;; `comp-cstr-ctxt-typeof-types' (or maybe even precompute them
|
(error "Type %S missing from typeof-types!" type)))
|
||||||
;; and maybe turn `comp-cstr-ctxt-typeof-types' into a hash-table).
|
|
||||||
;; Or maybe we shouldn't keep structs and defclasses in it,
|
|
||||||
;; and just use `cl--class-allparents' when needed (and refuse to
|
|
||||||
;; compute their direct subtypes since we can't know them).
|
|
||||||
(cl-loop
|
|
||||||
named loop
|
|
||||||
with above
|
|
||||||
for lane in (comp-cstr-ctxt-typeof-types comp-ctxt)
|
|
||||||
do (let ((x (memq type lane)))
|
|
||||||
(cond
|
|
||||||
((null x) nil)
|
|
||||||
((eq x lane) (cl-return-from loop x)) ;A base type: easy case.
|
|
||||||
(t (setq above
|
|
||||||
(if above (comp--intersection x above) x)))))
|
|
||||||
finally return above))
|
|
||||||
|
|
||||||
(defun comp-union-typesets (&rest typesets)
|
(defun comp-union-typesets (&rest typesets)
|
||||||
"Union types present into TYPESETS."
|
"Union types present into TYPESETS."
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ Abstract classes cannot be instantiated."
|
||||||
|
|
||||||
;; We autoload this because it's used in `make-autoload'.
|
;; We autoload this because it's used in `make-autoload'.
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun eieio-defclass-autoload (cname _superclasses filename doc)
|
(defun eieio-defclass-autoload (cname superclasses filename doc)
|
||||||
"Create autoload symbols for the EIEIO class CNAME.
|
"Create autoload symbols for the EIEIO class CNAME.
|
||||||
SUPERCLASSES are the superclasses that CNAME inherits from.
|
SUPERCLASSES are the superclasses that CNAME inherits from.
|
||||||
DOC is the docstring for CNAME.
|
DOC is the docstring for CNAME.
|
||||||
|
|
@ -199,15 +199,9 @@ This function creates a mock-class for CNAME and adds it into
|
||||||
SUPERCLASSES as children.
|
SUPERCLASSES as children.
|
||||||
It creates an autoload function for CNAME's constructor."
|
It creates an autoload function for CNAME's constructor."
|
||||||
;; Assume we've already debugged inputs.
|
;; Assume we've already debugged inputs.
|
||||||
|
|
||||||
;; We used to store the list of superclasses in the `parent' slot (as a list
|
|
||||||
;; of class names). But now this slot holds a list of class objects, and
|
|
||||||
;; those parents may not exist yet, so the corresponding class objects may
|
|
||||||
;; simply not exist yet. So instead we just don't store the list of parents
|
|
||||||
;; here in eieio-defclass-autoload at all, since it seems that they're just
|
|
||||||
;; not needed before the class is actually loaded.
|
|
||||||
(let* ((oldc (cl--find-class cname))
|
(let* ((oldc (cl--find-class cname))
|
||||||
(newc (eieio--class-make cname)))
|
(newc (eieio--class-make cname))
|
||||||
|
(parents (mapcar #'cl-find-class superclasses)))
|
||||||
(if (eieio--class-p oldc)
|
(if (eieio--class-p oldc)
|
||||||
nil ;; Do nothing if we already have this class.
|
nil ;; Do nothing if we already have this class.
|
||||||
|
|
||||||
|
|
@ -218,6 +212,12 @@ It creates an autoload function for CNAME's constructor."
|
||||||
use '%s or turn off `eieio-backward-compatibility' instead" cname)
|
use '%s or turn off `eieio-backward-compatibility' instead" cname)
|
||||||
"25.1"))
|
"25.1"))
|
||||||
|
|
||||||
|
(when (memq nil parents)
|
||||||
|
;; If some parents aren't yet fully defined, just ignore them for now.
|
||||||
|
(setq parents (delq nil parents)))
|
||||||
|
(unless parents
|
||||||
|
(setq parents (list (cl--find-class 'eieio-default-superclass))))
|
||||||
|
(setf (cl--class-parents newc) parents)
|
||||||
(setf (cl--find-class cname) newc)
|
(setf (cl--find-class cname) newc)
|
||||||
|
|
||||||
;; Create an autoload on top of our constructor function.
|
;; Create an autoload on top of our constructor function.
|
||||||
|
|
@ -958,19 +958,13 @@ need be... May remove that later...)"
|
||||||
(cdr tuple)
|
(cdr tuple)
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
(defsubst eieio--class/struct-parents (class)
|
|
||||||
(or (eieio--class-parents class)
|
|
||||||
`(,eieio-default-superclass)))
|
|
||||||
|
|
||||||
(defun eieio--class-precedence-c3 (class)
|
(defun eieio--class-precedence-c3 (class)
|
||||||
"Return all parents of CLASS in c3 order."
|
"Return all parents of CLASS in c3 order."
|
||||||
(let ((parents (eieio--class-parents class)))
|
(let ((parents (eieio--class-parents class)))
|
||||||
(cons class
|
(cons class
|
||||||
(merge-ordered-lists
|
(merge-ordered-lists
|
||||||
(append
|
(append
|
||||||
(or
|
(mapcar #'eieio--class-precedence-c3 parents)
|
||||||
(mapcar #'eieio--class-precedence-c3 parents)
|
|
||||||
`((,eieio-default-superclass)))
|
|
||||||
(list parents))
|
(list parents))
|
||||||
(lambda (remaining-inputs)
|
(lambda (remaining-inputs)
|
||||||
(signal 'inconsistent-class-hierarchy
|
(signal 'inconsistent-class-hierarchy
|
||||||
|
|
@ -984,13 +978,11 @@ need be... May remove that later...)"
|
||||||
(classes (copy-sequence
|
(classes (copy-sequence
|
||||||
(apply #'append
|
(apply #'append
|
||||||
(list class)
|
(list class)
|
||||||
(or
|
(mapcar
|
||||||
(mapcar
|
(lambda (parent)
|
||||||
(lambda (parent)
|
(cons parent
|
||||||
(cons parent
|
(eieio--class-precedence-dfs parent)))
|
||||||
(eieio--class-precedence-dfs parent)))
|
parents))))
|
||||||
parents)
|
|
||||||
`((,eieio-default-superclass))))))
|
|
||||||
(tail classes))
|
(tail classes))
|
||||||
;; Remove duplicates.
|
;; Remove duplicates.
|
||||||
(while tail
|
(while tail
|
||||||
|
|
@ -1003,13 +995,12 @@ need be... May remove that later...)"
|
||||||
(defun eieio--class-precedence-bfs (class)
|
(defun eieio--class-precedence-bfs (class)
|
||||||
"Return all parents of CLASS in breadth-first order."
|
"Return all parents of CLASS in breadth-first order."
|
||||||
(let* ((result)
|
(let* ((result)
|
||||||
(queue (eieio--class/struct-parents class)))
|
(queue (eieio--class-parents class)))
|
||||||
(while queue
|
(while queue
|
||||||
(let ((head (pop queue)))
|
(let ((head (pop queue)))
|
||||||
(unless (member head result)
|
(unless (member head result)
|
||||||
(push head result)
|
(push head result)
|
||||||
(unless (eq head eieio-default-superclass)
|
(setq queue (append queue (eieio--class-parents head))))))
|
||||||
(setq queue (append queue (eieio--class/struct-parents head)))))))
|
|
||||||
(cons class (nreverse result)))
|
(cons class (nreverse result)))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1049,6 +1040,14 @@ method invocation orders of the involved classes."
|
||||||
|
|
||||||
;;;; General support to dispatch based on the type of the argument.
|
;;;; General support to dispatch based on the type of the argument.
|
||||||
|
|
||||||
|
;; FIXME: We could almost use the typeof-generalizer (i.e. the same as
|
||||||
|
;; used for cl-structs), except that that generalizer doesn't support
|
||||||
|
;; `:method-invocation-order' :-(
|
||||||
|
|
||||||
|
(defun cl--generic-struct-tag (name &rest _)
|
||||||
|
;; Use exactly the same code as for `typeof'.
|
||||||
|
`(if ,name (type-of ,name) 'null))
|
||||||
|
|
||||||
(cl-generic-define-generalizer eieio--generic-generalizer
|
(cl-generic-define-generalizer eieio--generic-generalizer
|
||||||
;; Use the exact same tagcode as for cl-struct, so that methods
|
;; Use the exact same tagcode as for cl-struct, so that methods
|
||||||
;; that dispatch on both kinds of objects get to share this
|
;; that dispatch on both kinds of objects get to share this
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue