Function: cl-deftype
cl-deftype is an autoloaded macro defined in cl-macs.el.gz.
Signature
(cl-deftype NAME ARGLIST &rest BODY)
Documentation
Define NAME as a new, so-called derived type.
The type NAME can then be used in cl-typecase, cl-check-type,
etc., and to some extent, as method specializer.
ARGLIST is a Common Lisp argument list of the sort accepted by
cl-defmacro. BODY forms should return a type specifier that is equivalent
to the type (see the Info node (cl)Type Predicates).
If there is a declare form in BODY, the spec (parents . PARENTS)
can specify a list of types NAME is a subtype of.
The list of PARENTS types determines the order of methods invocation,
and missing PARENTS may cause incorrect ordering of methods, while
extraneous PARENTS may cause use of extraneous methods.
If PARENTS is non-nil, ARGLIST must be nil.
Probably introduced at or before Emacs version 31.1.
Aliases
deftype (obsolete since 27.1)
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/cl-macs.el.gz
;;; Types and assertions.
;;;###autoload
(defmacro cl-deftype (name arglist &rest body)
"Define NAME as a new, so-called derived type.
The type NAME can then be used in `cl-typecase', `cl-check-type',
etc., and to some extent, as method specializer.
ARGLIST is a Common Lisp argument list of the sort accepted by
`cl-defmacro'. BODY forms should return a type specifier that is equivalent
to the type (see the Info node `(cl)Type Predicates').
If there is a `declare' form in BODY, the spec (parents . PARENTS)
can specify a list of types NAME is a subtype of.
The list of PARENTS types determines the order of methods invocation,
and missing PARENTS may cause incorrect ordering of methods, while
extraneous PARENTS may cause use of extraneous methods.
If PARENTS is non-nil, ARGLIST must be nil."
(declare (debug cl-defmacro) (doc-string 3) (indent 2))
(pcase-let*
((`(,decls . ,forms) (macroexp-parse-body body))
(declares (assq 'declare decls))
(parent-decl (assq 'parents (cdr declares)))
(parents (cdr parent-decl)))
(when parent-decl
;; "Consume" the `parents' declaration.
(cl-callf (lambda (x) (delq parent-decl x)) (cdr declares))
(when (equal declares '(declare))
(cl-callf (lambda (x) (delq declares x)) decls)))
(let* ((expander
`(cl-function
(lambda (&cl-defs ('*) ,@arglist) ,@decls ,@forms)))
(specifier
(condition-case nil
;; FIXME: Pass a better lexical context.
(funcall (eval expander t))
;; We previously signaled an error when the type specified
;; both non-nil parents and arglist, like `unsigned-byte'
;; in below example:
;;
;; (cl-deftype my-integer ()
;; 'integer)
;;
;; (cl-deftype unsigned-byte (&optional bits)
;; "Unsigned integer."
;; (declare (parents my-integer))
;; `(integer 0 ,(if (memq bits '(nil *))
;; bits
;; (1- (ash 1 bits)))))
;;
;; In order to accept the above (correct) definition of
;; `unsigned-byte', call the expander without arguments to
;; check if the arglist is mandatory by catching a
;; `wrong-number-of-arguments' error. If so, and the type
;; specified both parents and arglist, there is a good
;; chance that the type is not atomic, so signal it;
;; otherwise, return nil as previously. Report any other
;; error on type definition.
(wrong-number-of-arguments
(and parents arglist ;; type is not atomic
(error "Type %S with parents may be not atomic: %S"
name arglist)))))
(predicate
(pcase specifier
(`(satisfies ,f) `#',f)
('nil nil)
(type `(lambda (x) (ignore x) (cl-typep x ',type))))))
`(eval-and-compile
(cl--define-derived-type
',name ,expander ,predicate ',parents)))))