Commit 59b5723c authored by Stefan Monnier's avatar Stefan Monnier
Browse files

Add online-help support to describe types

* lisp/help-fns.el (describe-symbol-backends): Move to help-mode.el.
(describe-symbol): Improve the selection of default.

* lisp/help-mode.el: Require cl-lib.
(describe-symbol-backends): Move from help-fns.el.
(help-make-xrefs): Use it.

* lisp/emacs-lisp/cl-extra.el (describe-symbol-backends): Add entry
for types.
(cl--typedef-regexp): New const.
(find-function-regexp-alist): Add entry for types.
(cl-help-type, cl-type-definition): New buttons.
(cl-find-class): New function.
(cl-describe-type): New command.
(cl--describe-class, cl--describe-class-slot)
(cl--describe-class-slots): New functions, moved from eieio-opt.el.

* lisp/emacs-lisp/cl-generic.el (cl--generic-method-documentation)
(cl--generic-all-functions, cl--generic-specializers-apply-to-type-p):
New functions.  Moved from eieio-opt.el.
(cl--generic-class-parents): New function, extracted from
cl--generic-struct-specializers.
(cl--generic-struct-specializers): Use it.

* lisp/emacs-lisp/cl-macs.el (cl-defstruct): Use pcase-dolist.
Improve constructor's docstrings.
(cl-struct-unknown-slot): New error.
(cl-struct-slot-offset): Use it.

* lisp/emacs-lisp/cl-preloaded.el (cl-struct-define): Record the type
definition in current-load-list.

* lisp/emacs-lisp/eieio-core.el (eieio--known-slot-names): New var.
(eieio--add-new-slot): Set it.
(eieio-defclass-internal): Use new name for current-load-list.
(eieio-oref): Add compiler-macro to warn about unknown slots.
* lisp/emacs-lisp/eieio.el (defclass): Update eieio--known-slot-names
as compile-time as well.  Improve constructor docstrings.

* lisp/emacs-lisp/eieio-opt.el (eieio-help-class)
(eieio--help-print-slot, eieio-help-class-slots): Move to cl-extra.el.
(eieio-class-def): Remove button.
(eieio-help-constructor): Use new name for load-history element.
(eieio--specializers-apply-to-class-p, eieio-all-generic-functions)
(eieio-method-documentation): Move to cl-generic.el.
(eieio-display-method-list): Use new names.

* lisp/emacs-lisp/lisp-mode.el (lisp-imenu-generic-expression):
Add "define-linline".
(lisp-fdefs): Remove "defsubst".
(el-fdefs): Add "defsubst", "cl-defsubst", and "define-linline".

* lisp/emacs-lisp/macroexp.el (macroexp--warned): New var.
(macroexp--warn-and-return): Use it to avoid inf-loops.
Add `compile-only' argument.
parent 287bce98
......@@ -688,6 +688,169 @@ including `cl-block' and `cl-eval-when'."
(prog1 (cl-prettyprint form)
(message ""))))
;;; Integration into the online help system.
(eval-when-compile (require 'cl-macs)) ;Explicitly, for cl--find-class.
(require 'help-mode)
;; FIXME: We could go crazy and add another entry so describe-symbol can be
;; used with the slot names of CL structs (and/or EIEIO objects).
(add-to-list 'describe-symbol-backends
`(nil ,#'cl-find-class ,(lambda (s _b _f) (cl-describe-type s))))
(defconst cl--typedef-regexp
(concat "(" (regexp-opt '("defclass" "defstruct" "cl-defstruct"
"cl-deftype" "deftype"))
"[ \t\r\n]+%s[ \t\r\n]+"))
(with-eval-after-load 'find-func
(defvar find-function-regexp-alist)
(add-to-list 'find-function-regexp-alist
`(define-type . cl--typedef-regexp)))
(define-button-type 'cl-help-type
:supertype 'help-function-def
'help-function #'cl-describe-type
'help-echo (purecopy "mouse-2, RET: describe this type"))
(define-button-type 'cl-type-definition
:supertype 'help-function-def
'help-echo (purecopy "mouse-2, RET: find type definition"))
(declare-function help-fns-short-filename "help-fns" (filename))
;;;###autoload
(defun cl-find-class (type) (cl--find-class type))
;;;###autoload
(defun cl-describe-type (type)
"Display the documentation for type TYPE (a symbol)."
(interactive
(let ((str (completing-read "Describe type: " obarray #'cl-find-class t)))
(if (<= (length str) 0)
(user-error "Abort!")
(list (intern str)))))
(help-setup-xref (list #'cl-describe-type type)
(called-interactively-p 'interactive))
(save-excursion
(with-help-window (help-buffer)
(with-current-buffer standard-output
(let ((class (cl-find-class type)))
(if class
(cl--describe-class type class)
;; FIXME: Describe other types (the built-in ones, or those from
;; cl-deftype).
(user-error "Unknown type %S" type))))
(with-current-buffer standard-output
;; Return the text we displayed.
(buffer-string)))))
(defun cl--describe-class (type &optional class)
(unless class (setq class (cl--find-class type)))
(let ((location (find-lisp-object-file-name type 'define-type))
;; FIXME: Add a `cl-class-of' or `cl-typeof' or somesuch.
(metatype (cl--class-name (symbol-value (aref class 0)))))
(insert (symbol-name type)
(substitute-command-keys " is a type (of kind ‘"))
(help-insert-xref-button (symbol-name metatype)
'cl-help-type metatype)
(insert (substitute-command-keys "’)"))
(when location
(insert (substitute-command-keys " in ‘"))
(help-insert-xref-button
(help-fns-short-filename location)
'cl-type-definition type location 'define-type)
(insert (substitute-command-keys "’")))
(insert ".\n")
;; Parents.
(let ((pl (cl--class-parents class))
cur)
(when pl
(insert " Inherits from ")
(while (setq cur (pop pl))
(setq cur (cl--class-name cur))
(insert (substitute-command-keys "‘"))
(help-insert-xref-button (symbol-name cur)
'cl-help-type cur)
(insert (substitute-command-keys (if pl "’, " "’"))))
(insert ".\n")))
;; Children, if available. ¡For EIEIO!
(let ((ch (condition-case nil
(cl-struct-slot-value metatype 'children class)
(cl-struct-unknown-slot nil)))
cur)
(when ch
(insert " Children ")
(while (setq cur (pop ch))
(insert (substitute-command-keys "‘"))
(help-insert-xref-button (symbol-name cur)
'cl-help-type cur)
(insert (substitute-command-keys (if ch "’, " "’"))))
(insert ".\n")))
;; Type's documentation.
(let ((doc (cl--class-docstring class)))
(when doc
(insert "\n" doc "\n\n")))
;; Describe all the slots in this class.
(cl--describe-class-slots class)
;; Describe all the methods specific to this class.
(let ((generics (cl--generic-all-functions type)))
(when generics
(insert (propertize "Specialized Methods:\n\n" 'face 'bold))
(dolist (generic generics)
(insert (substitute-command-keys "‘"))
(help-insert-xref-button (symbol-name generic)
'help-function generic)
(insert (substitute-command-keys "’"))
(pcase-dolist (`(,qualifiers ,args ,doc)
(cl--generic-method-documentation generic type))
(insert (format " %s%S\n" qualifiers args)
(or doc "")))
(insert "\n\n"))))))
(defun cl--describe-class-slot (slot)
(insert
(concat
(propertize "Slot: " 'face 'bold)
(prin1-to-string (cl--slot-descriptor-name slot))
(unless (eq (cl--slot-descriptor-type slot) t)
(concat " type = "
(prin1-to-string (cl--slot-descriptor-type slot))))
;; FIXME: The default init form is treated differently for structs and for
;; eieio objects: for structs, the default is nil, for eieio-objects
;; it's a special "unbound" value.
(unless nil ;; (eq (cl--slot-descriptor-initform slot) eieio-unbound)
(concat " default = "
(prin1-to-string (cl--slot-descriptor-initform slot))))
(when (alist-get :printer (cl--slot-descriptor-props slot))
(concat " printer = "
(prin1-to-string
(alist-get :printer (cl--slot-descriptor-props slot)))))
(when (alist-get :documentation (cl--slot-descriptor-props slot))
(concat "\n " (alist-get :documentation (cl--slot-descriptor-props slot))
"\n")))
"\n"))
(defun cl--describe-class-slots (class)
"Print help description for the slots in CLASS.
Outputs to the current buffer."
(let* ((slots (cl--class-slots class))
;; FIXME: Add a `cl-class-of' or `cl-typeof' or somesuch.
(metatype (cl--class-name (symbol-value (aref class 0))))
;; ¡For EIEIO!
(cslots (condition-case nil
(cl-struct-slot-value metatype 'class-slots class)
(cl-struct-unknown-slot nil))))
(insert (propertize "Instance Allocated Slots:\n\n"
'face 'bold))
(mapc #'cl--describe-class-slot slots)
(when (> (length cslots) 0)
(insert (propertize "\nClass Allocated Slots:\n\n" 'face 'bold))
(mapc #'cl--describe-class-slot cslots))))
(run-hooks 'cl-extra-load-hook)
......
......@@ -95,6 +95,7 @@
;; usually be simplified, or even completely skipped.
(eval-when-compile (require 'cl-lib))
(eval-when-compile (require 'cl-macs)) ;For cl--find-class.
(eval-when-compile (require 'pcase))
(cl-defstruct (cl--generic-generalizer
......@@ -883,6 +884,55 @@ Can only be used from within the lexical body of a primary or around method."
(insert (substitute-command-keys "’.\n"))))
(insert "\n" (or (nth 2 info) "Undocumented") "\n\n")))))))
(defun cl--generic-specializers-apply-to-type-p (specializers type)
"Return non-nil if a method with SPECIALIZERS applies to TYPE."
(let ((applies nil))
(dolist (specializer specializers)
(if (memq (car-safe specializer) '(subclass eieio--static))
(setq specializer (nth 1 specializer)))
;; Don't include the methods that are "too generic", such as those
;; applying to `eieio-default-superclass'.
(and (not (memq specializer '(t eieio-default-superclass)))
(or (equal type specializer)
(when (symbolp specializer)
(let ((sclass (cl--find-class specializer))
(tclass (cl--find-class type)))
(when (and sclass tclass)
(member specializer (cl--generic-class-parents tclass))))))
(setq applies t)))
applies))
(defun cl--generic-all-functions (&optional type)
"Return a list of all generic functions.
Optional TYPE argument returns only those functions that contain
methods for TYPE."
(let ((l nil))
(mapatoms
(lambda (symbol)
(let ((generic (and (fboundp symbol) (cl--generic symbol))))
(and generic
(catch 'found
(if (null type) (throw 'found t))
(dolist (method (cl--generic-method-table generic))
(if (cl--generic-specializers-apply-to-type-p
(cl--generic-method-specializers method) type)
(throw 'found t))))
(push symbol l)))))
l))
(defun cl--generic-method-documentation (function type)
"Return info for all methods of FUNCTION (a symbol) applicable to TYPE.
The value returned is a list of elements of the form
\(QUALIFIERS ARGS DOC)."
(let ((generic (cl--generic function))
(docs ()))
(when generic
(dolist (method (cl--generic-method-table generic))
(when (cl--generic-specializers-apply-to-type-p
(cl--generic-method-specializers method) type)
(push (cl--generic-method-info method) docs))))
docs))
;;; Support for (head <val>) specializers.
;; For both the `eql' and the `head' specializers, the dispatch
......@@ -958,19 +1008,22 @@ Can only be used from within the lexical body of a primary or around method."
(if (eq (symbol-function tag) :quick-object-witness-check)
tag))))
(defun cl--generic-class-parents (class)
(let ((parents ())
(classes (list class)))
;; BFS precedence. FIXME: Use a topological sort.
(while (let ((class (pop classes)))
(cl-pushnew (cl--class-name class) parents)
(setq classes
(append classes
(cl--class-parents class)))))
(nreverse parents)))
(defun cl--generic-struct-specializers (tag)
(and (symbolp tag) (boundp tag)
(let ((class (symbol-value tag)))
(when (cl-typep class 'cl-structure-class)
(let ((types ())
(classes (list class)))
;; BFS precedence.
(while (let ((class (pop classes)))
(push (cl--class-name class) types)
(setq classes
(append classes
(cl--class-parents class)))))
(nreverse types))))))
(cl--generic-class-parents class)))))
(defconst cl--generic-struct-generalizer
(cl-generic-make-generalizer
......
......@@ -2722,20 +2722,16 @@ non-nil value, that slot cannot be set via `setf'.
(push `(defalias ',copier #'copy-sequence) forms))
(if constructor
(push (list constructor
(cons '&key (delq nil (copy-sequence slots))))
constrs))
(while constrs
(let* ((name (caar constrs))
(rest (cdr (pop constrs)))
(args (car rest))
(doc (cadr rest))
(anames (cl--arglist-args args))
(cons '&key (delq nil (copy-sequence slots))))
constrs))
(pcase-dolist (`(,cname ,args ,doc) constrs)
(let* ((anames (cl--arglist-args args))
(make (cl-mapcar (function (lambda (s d) (if (memq s anames) s d)))
slots defaults)))
(push `(cl-defsubst ,name
(push `(cl-defsubst ,cname
(&cl-defs (nil ,@descs) ,@args)
,@(if (stringp doc) (list doc)
(if (stringp docstring) (list docstring)))
,(if (stringp doc) (list doc)
(format "Constructor for objects of type `%s'." name))
,@(if (cl--safe-expr-p `(progn ,@(mapcar #'cl-second descs)))
'((declare (side-effect-free t))))
(,(or type #'vector) ,@make))
......@@ -2859,6 +2855,8 @@ slots skipped by :initial-offset may appear in the list."
descs)))
(nreverse descs)))
(define-error 'cl-struct-unknown-slot "struct %S has no slot %S")
(defun cl-struct-slot-offset (struct-type slot-name)
"Return the offset of slot SLOT-NAME in STRUCT-TYPE.
The returned zero-based slot index is relative to the start of
......@@ -2868,7 +2866,7 @@ does not contain SLOT-NAME."
(declare (side-effect-free t) (pure t))
(or (gethash slot-name
(cl--class-index-table (cl--struct-get-class struct-type)))
(error "struct %s has no slot %s" struct-type slot-name)))
(signal 'cl-struct-unknown-slot (list struct-type slot-name))))
(defvar byte-compile-function-environment)
(defvar byte-compile-macro-environment)
......
......@@ -147,6 +147,7 @@
ok)
(error "Included struct %S has changed since compilation of %S"
parent name))))
(add-to-list 'current-load-list `(define-type . ,name))
(cl--struct-register-child parent-class tag)
(unless (eq named t)
(eval `(defconst ,tag ',class) t)
......
......@@ -261,6 +261,8 @@ It creates an autoload function for CNAME's constructor."
(and (eieio-object-p obj)
(object-of-class-p obj class))))
(defvar eieio--known-slot-names nil)
(defun eieio-defclass-internal (cname superclasses slots options)
"Define CNAME as a new subclass of SUPERCLASSES.
SLOTS are the slots residing in that class definition, and OPTIONS
......@@ -473,7 +475,7 @@ See `defclass' for more information."
(put cname 'variable-documentation docstring)))
;; Save the file location where this class is defined.
(add-to-list 'current-load-list `(eieio-defclass . ,cname))
(add-to-list 'current-load-list `(define-type . ,cname))
;; We have a list of custom groups. Store them into the options.
(let ((g (eieio--class-option-assoc options :custom-groups)))
......@@ -603,47 +605,48 @@ if default value is nil."
:key #'cl--slot-descriptor-name)))
(cold (car (cl-member a (eieio--class-class-slots newc)
:key #'cl--slot-descriptor-name))))
(condition-case nil
(if (sequencep d) (setq d (copy-sequence d)))
;; This copy can fail on a cons cell with a non-cons in the cdr. Let's
;; skip it if it doesn't work.
(error nil))
;; (if (sequencep type) (setq type (copy-sequence type)))
;; (if (sequencep cust) (setq cust (copy-sequence cust)))
;; (if (sequencep custg) (setq custg (copy-sequence custg)))
;; To prevent override information w/out specification of storage,
;; we need to do this little hack.
(if cold (setq alloc :class))
(if (memq alloc '(nil :instance))
;; In this case, we modify the INSTANCE version of a given slot.
(progn
;; Only add this element if it is so-far unique
(if (not old)
(progn
(eieio--perform-slot-validation-for-default slot skipnil)
(push slot (eieio--class-slots newc))
)
;; When defaultoverride is true, we are usually adding new local
;; attributes which must override the default value of any slot
;; passed in by one of the parent classes.
(when defaultoverride
(eieio--slot-override old slot skipnil)))
(when init
(cl-pushnew (cons init a) (eieio--class-initarg-tuples newc)
:test #'equal)))
;; CLASS ALLOCATED SLOTS
(if (not cold)
(cl-pushnew a eieio--known-slot-names)
(condition-case nil
(if (sequencep d) (setq d (copy-sequence d)))
;; This copy can fail on a cons cell with a non-cons in the cdr. Let's
;; skip it if it doesn't work.
(error nil))
;; (if (sequencep type) (setq type (copy-sequence type)))
;; (if (sequencep cust) (setq cust (copy-sequence cust)))
;; (if (sequencep custg) (setq custg (copy-sequence custg)))
;; To prevent override information w/out specification of storage,
;; we need to do this little hack.
(if cold (setq alloc :class))
(if (memq alloc '(nil :instance))
;; In this case, we modify the INSTANCE version of a given slot.
(progn
(eieio--perform-slot-validation-for-default slot skipnil)
;; Here we have found a :class version of a slot. This
;; requires a very different approach.
(push slot (eieio--class-class-slots newc)))
(when defaultoverride
;; There is a match, and we must override the old value.
(eieio--slot-override cold slot skipnil))))))
;; Only add this element if it is so-far unique
(if (not old)
(progn
(eieio--perform-slot-validation-for-default slot skipnil)
(push slot (eieio--class-slots newc))
)
;; When defaultoverride is true, we are usually adding new local
;; attributes which must override the default value of any slot
;; passed in by one of the parent classes.
(when defaultoverride
(eieio--slot-override old slot skipnil)))
(when init
(cl-pushnew (cons init a) (eieio--class-initarg-tuples newc)
:test #'equal)))
;; CLASS ALLOCATED SLOTS
(if (not cold)
(progn
(eieio--perform-slot-validation-for-default slot skipnil)
;; Here we have found a :class version of a slot. This
;; requires a very different approach.
(push slot (eieio--class-class-slots newc)))
(when defaultoverride
;; There is a match, and we must override the old value.
(eieio--slot-override cold slot skipnil))))))
(defun eieio-copy-parents-into-subclass (newc)
"Copy into NEWC the slots of PARENTS.
......@@ -720,9 +723,18 @@ Argument FN is the function calling this verifier."
;;; Get/Set slots in an object.
;;
(defun eieio-oref (obj slot)
"Return the value in OBJ at SLOT in the object vector."
(declare (compiler-macro
(lambda (exp)
(ignore obj)
(pcase slot
((and (or `',name (and name (pred keywordp)))
(guard (not (memq name eieio--known-slot-names))))
(macroexp--warn-and-return
(format "Unknown slot `%S'" name) exp 'compile-only))
(_ exp)))))
(cl-check-type slot symbol)
(cl-check-type obj (or eieio-object class))
(let* ((class (cond ((symbolp obj)
......
......@@ -31,7 +31,6 @@
(require 'eieio)
(require 'find-func)
(require 'speedbar)
(require 'help-mode)
;;; Code:
;;;###autoload
......@@ -78,101 +77,7 @@ Argument CH-PREFIX is another character prefix to display."
(declare-function help-fns-short-filename "help-fns" (filename))
;;;###autoload
(defun eieio-help-class (class)
"Print help description for CLASS.
If CLASS is actually an object, then also display current values of that object."
;; Header line
(prin1 class)
(insert " is a"
(if (eieio--class-option (cl--find-class class) :abstract)
"n abstract"
"")
" class")
(let ((location (find-lisp-object-file-name class 'eieio-defclass)))
(when location
(insert (substitute-command-keys " in ‘"))
(help-insert-xref-button
(help-fns-short-filename location)
'eieio-class-def class location 'eieio-defclass)
(insert (substitute-command-keys "’"))))
(insert ".\n")
;; Parents
(let ((pl (eieio-class-parents class))
cur)
(when pl
(insert " Inherits from ")
(while (setq cur (pop pl))
(setq cur (eieio--class-name cur))
(insert (substitute-command-keys "‘"))
(help-insert-xref-button (symbol-name cur)
'help-function cur)
(insert (substitute-command-keys (if pl "’, " "’"))))
(insert ".\n")))
;; Children
(let ((ch (eieio-class-children class))
cur)
(when ch
(insert " Children ")
(while (setq cur (pop ch))
(insert (substitute-command-keys "‘"))
(help-insert-xref-button (symbol-name cur)
'help-function cur)
(insert (substitute-command-keys (if ch "’, " "’"))))
(insert ".\n")))
;; System documentation
(let ((doc (documentation-property class 'variable-documentation)))
(when doc
(insert "\n" doc "\n\n")))
;; Describe all the slots in this class.
(eieio-help-class-slots class)
;; Describe all the methods specific to this class.
(let ((generics (eieio-all-generic-functions class)))
(when generics
(insert (propertize "Specialized Methods:\n\n" 'face 'bold))
(dolist (generic generics)
(insert (substitute-command-keys "‘"))
(help-insert-xref-button (symbol-name generic) 'help-function generic)
(insert (substitute-command-keys "’"))
(pcase-dolist (`(,qualifiers ,args ,doc)
(eieio-method-documentation generic class))
(insert (format " %s%S\n" qualifiers args)
(or doc "")))
(insert "\n\n")))))
(defun eieio--help-print-slot (slot)
(insert
(concat
(propertize "Slot: " 'face 'bold)
(prin1-to-string (cl--slot-descriptor-name slot))
(unless (eq (cl--slot-descriptor-type slot) t)
(concat " type = "
(prin1-to-string (cl--slot-descriptor-type slot))))
(unless (eq (cl--slot-descriptor-initform slot) eieio-unbound)
(concat " default = "
(prin1-to-string (cl--slot-descriptor-initform slot))))
(when (alist-get :printer (cl--slot-descriptor-props slot))
(concat " printer = "
(prin1-to-string
(alist-get :printer (cl--slot-descriptor-props slot)))))
(when (alist-get :documentation (cl--slot-descriptor-props slot))
(concat "\n " (alist-get :documentation (cl--slot-descriptor-props slot))
"\n")))
"\n"))
(defun eieio-help-class-slots (class)
"Print help description for the slots in CLASS.
Outputs to the current buffer."
(let* ((cv (cl--find-class class))
(slots (eieio--class-slots cv))
(cslots (eieio--class-class-slots cv)))
(insert (propertize "Instance Allocated Slots:\n\n"
'face 'bold))
(dotimes (i (length slots))
(eieio--help-print-slot (aref slots i)))
(when (> (length cslots) 0)
(insert (propertize "\nClass Allocated Slots:\n\n" 'face 'bold)))
(dotimes (i (length cslots))
(eieio--help-print-slot (aref cslots i)))))
(define-obsolete-function-alias 'eieio-help-class 'cl--describe-class "25.1")
(defun eieio-build-class-alist (&optional class instantiable-only buildlist)
"Return an alist of all currently active classes for completion purposes.
......@@ -217,22 +122,13 @@ are not abstract."
;;; METHOD COMPLETION / DOC
(define-button-type 'eieio-class-def
:supertype 'help-function-def
'help-echo (purecopy "mouse-2, RET: find class definition"))
(defconst eieio--defclass-regexp "(defclass[ \t\r\n]+%s[ \t\r\n]+")
(with-eval-after-load 'find-func
(defvar find-function-regexp-alist)
(add-to-list 'find-function-regexp-alist
`(eieio-defclass . eieio--defclass-regexp)))
;;;###autoload
(defun eieio-help-constructor (ctr)
"Describe CTR if it is a class constructor."
(when (class-p ctr)
(erase-buffer)
(let ((location (find-lisp-object-file-name ctr 'eieio-defclass))
(let ((location (find-lisp-object-file-name ctr 'define-type))
(def (symbol-function ctr)))
(goto-char (point-min))
(prin1 ctr)
......@@ -248,7 +144,7 @@ are not abstract."
(insert (substitute-command-keys " in ‘"))
(help-insert-xref-button
(help-fns-short-filename location)
'eieio-class-def ctr location 'eieio-defclass)
'cl-type-definition ctr location 'define-type)
(insert (substitute-command-keys "’")))
(insert ".\nCreates an object of class " (symbol-name ctr) ".")
(goto-char (point-max))
......@@ -259,50 +155,6 @@ are not abstract."
(eieio-help-class ctr))
))))
(defun eieio--specializers-apply-to-class-p (specializers class)
"Return non-nil if a method with SPECIALIZERS applies to CLASS."
(let ((applies nil))
(dolist (specializer specializers)
(if (memq (car-safe specializer) '(subclass eieio--static))
(setq specializer (nth 1 specializer)))
;; Don't include the methods that are "too generic", such as those
;; applying to `eieio-default-superclass'.
(and (not (memq specializer '(t eieio-default-superclass)))
(class-p specializer)
(child-of-class-p class specializer)