aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/misc/cl.texi28
-rw-r--r--lisp/emacs-lisp/cl-extra.el47
-rw-r--r--lisp/emacs-lisp/cl-lib.el12
-rw-r--r--lisp/emacs-lisp/cl-macs.el13
-rw-r--r--lisp/emacs-lisp/cl-preloaded.el22
5 files changed, 73 insertions, 49 deletions
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index 4bceddb8196..a1246b11a8a 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -888,8 +888,12 @@ floats. In all other circumstances, @code{cl-coerce} signals an
888error. 888error.
889@end defun 889@end defun
890 890
891@defmac cl-deftype name arglist forms@dots{} 891@node Derived types
892This macro defines a new type called @var{name}. It is similar 892@subsection Derived types
893
894@defmac cl-deftype name arglist [docstring] [decls] forms@dots{}
895This macro defines a new type called @var{name}.
896Types defined this way are called @dfn{derived types}. It is similar
893to @code{defmacro} in many ways; when @var{name} is encountered 897to @code{defmacro} in many ways; when @var{name} is encountered
894as a type name, the body @var{forms} are evaluated and should 898as a type name, the body @var{forms} are evaluated and should
895return a type specifier that is equivalent to the type. The 899return a type specifier that is equivalent to the type. The
@@ -923,6 +927,26 @@ The @code{cl-typecase} (@pxref{Conditionals}) and @code{cl-check-type}
923@code{cl-concatenate}, and @code{cl-merge} functions take type-name 927@code{cl-concatenate}, and @code{cl-merge} functions take type-name
924arguments to specify the type of sequence to return. @xref{Sequences}. 928arguments to specify the type of sequence to return. @xref{Sequences}.
925 929
930Contrary to Common Lisp, CL-Lib supports the use of derived types
931as method specializers. This comes with a significant caveat: derived
932types are much too flexible for Emacs to be able to automatically find
933out which type is a subtype of another, so the ordering of
934methods is not well-defined when several methods are applicable for
935a given argument value and the specializer of one or more of those
936methods is a derived type. To make the order more well-defined, a derived type
937definition can explicitly state that it is a subtype of others using the
938@var{decls} argument:
939
940@example
941(cl-deftype unsigned-byte (&optional bits)
942 (list 'integer 0 (if (eq bits '*) bits (1- (ash 1 bits)))))
943
944(cl-deftype unsigned-8bits ()
945 "Unsigned 8-bits integer."
946 (declare (parents unsigned-byte))
947 '(unsigned-byte 8))
948@end example
949
926@node Equality Predicates 950@node Equality Predicates
927@section Equality Predicates 951@section Equality Predicates
928 952
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index f232f06718e..b3886b5bde3 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -965,7 +965,7 @@ Outputs to the current buffer."
965 (insert (propertize "\nClass Allocated Slots:\n\n" 'face 'bold)) 965 (insert (propertize "\nClass Allocated Slots:\n\n" 'face 'bold))
966 (mapc #'cl--describe-class-slot cslots)))) 966 (mapc #'cl--describe-class-slot cslots))))
967 967
968;;;; Method dispatch on `cl-deftype' types. 968;;;; Method dispatch on `cl-deftype' types (a.k.a "derived types").
969 969
970;; Extend `cl-deftype' to define data types which are also valid 970;; Extend `cl-deftype' to define data types which are also valid
971;; argument types for dispatching generic function methods (see also 971;; argument types for dispatching generic function methods (see also
@@ -978,8 +978,8 @@ Outputs to the current buffer."
978;; - `cl-types-of', that returns the types an object belongs to. 978;; - `cl-types-of', that returns the types an object belongs to.
979 979
980;; Ensure each type satisfies `eql'. 980;; Ensure each type satisfies `eql'.
981(defvar cl--type-unique (make-hash-table :test 'equal) 981(defvar cl--types-of-memo (make-hash-table :test 'equal)
982 "Record an unique value of each type.") 982 "Memoization table used in `cl-types-of'.")
983 983
984;; FIXME: `cl-types-of' CPU cost is proportional to the number of types 984;; FIXME: `cl-types-of' CPU cost is proportional to the number of types
985;; defined with `cl-deftype', so the more popular it gets, the slower 985;; defined with `cl-deftype', so the more popular it gets, the slower
@@ -1007,9 +1007,12 @@ Outputs to the current buffer."
1007;; one of them (`cl-typep' itself being a recursive function that 1007;; one of them (`cl-typep' itself being a recursive function that
1008;; basically interprets the type language). This is going to slow 1008;; basically interprets the type language). This is going to slow
1009;; down dispatch very significantly for those generic functions that 1009;; down dispatch very significantly for those generic functions that
1010;; have a method that dispatches on a user defined type, compared to 1010;; have a method that dispatches on a derived type, compared to
1011;; those that don't. 1011;; those that don't.
1012;; 1012;;
1013;; As a simple optimization, the method dispatch tests only those
1014;; derived types which have been used as a specialize in a method.
1015;;
1013;; A possible further improvement: 1016;; A possible further improvement:
1014;; 1017;;
1015;; - based on the PARENTS declaration, create a map from builtin-type 1018;; - based on the PARENTS declaration, create a map from builtin-type
@@ -1019,19 +1022,18 @@ Outputs to the current buffer."
1019;; associated with the `t' "dummy parent". [ We could even go crazy 1022;; associated with the `t' "dummy parent". [ We could even go crazy
1020;; and try and guess PARENTS when not provided, by analyzing the 1023;; and try and guess PARENTS when not provided, by analyzing the
1021;; type's definition. ] 1024;; type's definition. ]
1022;;
1023;; - in `cl-types-of' start by calling `cl-type-of', then use the map 1025;; - in `cl-types-of' start by calling `cl-type-of', then use the map
1024;; to find which cl-types may need to be checked. 1026;; to find which cl-types may need to be checked.
1025;; 1027;;
1026;;;###autoload 1028;;;###autoload
1027(defun cl-types-of (object &optional types) 1029(defun cl-types-of (object &optional types)
1028 "Return the types OBJECT belongs to. 1030 "Return the atomic types OBJECT belongs to.
1029Return an unique list of types OBJECT belongs to, ordered from the 1031Return an unique list of types OBJECT belongs to, ordered from the
1030most specific type to the most general. 1032most specific type to the most general.
1031TYPES is an internal argument." 1033TYPES is an internal argument."
1032 (let* ((found nil)) 1034 (let* ((found nil))
1033 ;; Build a list of all types OBJECT belongs to. 1035 ;; Build a list of all types OBJECT belongs to.
1034 (dolist (type (or types cl--type-list)) 1036 (dolist (type (or types cl--derived-type-list))
1035 (and 1037 (and
1036 ;; If OBJECT is of type, add type to the matching list. 1038 ;; If OBJECT is of type, add type to the matching list.
1037 (if types 1039 (if types
@@ -1041,25 +1043,28 @@ TYPES is an internal argument."
1041 (cl-typep object type) 1043 (cl-typep object type)
1042 (condition-case-unless-debug e 1044 (condition-case-unless-debug e
1043 (cl-typep object type) 1045 (cl-typep object type)
1044 (error (setq cl--type-list (delq type cl--type-list)) 1046 (error (setq cl--derived-type-list (delq type cl--derived-type-list))
1045 (warn "cl-types-of %S: %s" 1047 (warn "cl-types-of %S: %s"
1046 type (error-message-string e)) 1048 type (error-message-string e))
1047 nil))) 1049 nil)))
1048 (push type found))) 1050 (push type found)))
1049 (push (cl-type-of object) found) 1051 (push (cl-type-of object) found)
1050 ;; Return an unique value of the list of types OBJECT belongs to, 1052 ;; Return the list of types OBJECT belongs to, which is also the list
1051 ;; which is also the list of specifiers for OBJECT. 1053 ;; of specifiers for OBJECT. This memoization has two purposes:
1052 (with-memoization (gethash found cl--type-unique) 1054 ;; - Speed up computation.
1055 ;; - Make sure we always return the same (eq) object, so that the
1056 ;; method dispatch's own caching works as it should.
1057 (with-memoization (gethash found cl--types-of-memo)
1053 ;; Compute an ordered list of types from the DAG. 1058 ;; Compute an ordered list of types from the DAG.
1054 (let (dag) 1059 (let (dag)
1055 (dolist (type found) 1060 (dolist (type found)
1056 (push (cl--class-allparents (cl--find-class type)) dag)) 1061 (push (cl--class-allparents (cl--find-class type)) dag))
1057 (merge-ordered-lists dag))))) 1062 (merge-ordered-lists dag)))))
1058 1063
1059(defvar cl--type-dispatch-list nil 1064(defvar cl--derived-type-dispatch-list nil
1060 "List of types that need to be checked during dispatch.") 1065 "List of types that need to be checked during dispatch.")
1061 1066
1062(cl-generic-define-generalizer cl--type-generalizer 1067(cl-generic-define-generalizer cl--derived-type-generalizer
1063 ;; FIXME: This priority can't be always right. :-( 1068 ;; FIXME: This priority can't be always right. :-(
1064 ;; E.g. a method dispatching on a type like (or number function), 1069 ;; E.g. a method dispatching on a type like (or number function),
1065 ;; should take precedence over a method on `t' but not over a method 1070 ;; should take precedence over a method on `t' but not over a method
@@ -1070,22 +1075,22 @@ TYPES is an internal argument."
1070 ;; suffer from "undefined method ordering" problems, unless/until we 1075 ;; suffer from "undefined method ordering" problems, unless/until we
1071 ;; restrict it somehow to a subset that we can handle reliably. 1076 ;; restrict it somehow to a subset that we can handle reliably.
1072 20 ;; "typeof" < "cl-types-of" < "head" priority 1077 20 ;; "typeof" < "cl-types-of" < "head" priority
1073 (lambda (obj &rest _) `(cl-types-of ,obj cl--type-dispatch-list)) 1078 (lambda (obj &rest _) `(cl-types-of ,obj cl--derived-type-dispatch-list))
1074 (lambda (tag &rest _) (if (consp tag) tag))) 1079 (lambda (tag &rest _) (if (consp tag) tag)))
1075 1080
1076;;;###autoload 1081;;;###autoload
1077(defun cl--type-generalizers (type) 1082(defun cl--derived-type-generalizers (type)
1078 ;; Add a new dispatch type to the dispatch list, then 1083 ;; Add a new dispatch type to the dispatch list, then
1079 ;; synchronize with `cl--type-list' so that both lists follow 1084 ;; synchronize with `cl--derived-type-list' so that both lists follow
1080 ;; the same type precedence order. 1085 ;; the same type precedence order.
1081 ;; The `merge-ordered-lists' is `cl-types-of' should we make this 1086 ;; The `merge-ordered-lists' is `cl-types-of' should we make this
1082 ;; ordering unnecessary, but it's still handy for all those types 1087 ;; ordering unnecessary, but it's still handy for all those types
1083 ;; that don't declare their parents. 1088 ;; that don't declare their parents.
1084 (unless (memq type cl--type-dispatch-list) 1089 (unless (memq type cl--derived-type-dispatch-list)
1085 (setq cl--type-dispatch-list 1090 (setq cl--derived-type-dispatch-list
1086 (seq-intersection cl--type-list 1091 (seq-intersection cl--derived-type-list
1087 (cons type cl--type-dispatch-list)))) 1092 (cons type cl--derived-type-dispatch-list))))
1088 (list cl--type-generalizer)) 1093 (list cl--derived-type-generalizer))
1089 1094
1090;;;; Trailer 1095;;;; Trailer
1091 1096
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index 2de81311380..7d013dfca5f 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -566,14 +566,14 @@ If ALIST is non-nil, the new pairs are prepended to it."
566 ;; Also, there is no mechanism to autoload methods, so this can't be 566 ;; Also, there is no mechanism to autoload methods, so this can't be
567 ;; moved to `cl-extra.el'. 567 ;; moved to `cl-extra.el'.
568 nil 568 nil
569 (declare-function cl--type-generalizers "cl-extra" (type)) 569 (declare-function cl--derived-type-generalizers "cl-extra" (type))
570 (cl-defmethod cl-generic-generalizers :extra "cl-types-of" (type) 570 (cl-defmethod cl-generic-generalizers :extra "derived-types" (type)
571 "Support for dispatch on cl-types." 571 "Support for dispatch on derived types, i.e. defined with `cl-deftype'."
572 (if (and (symbolp type) (cl-type-class-p (cl--find-class type)) 572 (if (and (symbolp type) (cl-derived-type-class-p (cl--find-class type))
573 ;; Make sure this derived type can be used without arguments. 573 ;; Make sure this derived type can be used without arguments.
574 (let ((expander (get type 'cl-deftype-handler))) 574 (let ((expander (get type 'cl-deftype-handler)))
575 (and expander (ignore-errors (funcall expander))))) 575 (and expander (with-demoted-errors "%S" (funcall expander)))))
576 (cl--type-generalizers type) 576 (cl--derived-type-generalizers type)
577 (cl-call-next-method)))) 577 (cl-call-next-method))))
578 578
579(defun cl--old-struct-type-of (orig-fun object) 579(defun cl--old-struct-type-of (orig-fun object)
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 424ebe2c7ad..0fc791890aa 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -3785,7 +3785,7 @@ macro that returns its `&whole' argument."
3785 3785
3786;;;###autoload 3786;;;###autoload
3787(defmacro cl-deftype (name arglist &rest body) 3787(defmacro cl-deftype (name arglist &rest body)
3788 "Define NAME as a new data type. 3788 "Define NAME as a new, so-called derived type.
3789The type NAME can then be used in `cl-typecase', `cl-check-type', 3789The type NAME can then be used in `cl-typecase', `cl-check-type',
3790etc., and to some extent, as method specializer. 3790etc., and to some extent, as method specializer.
3791 3791
@@ -3816,20 +3816,15 @@ If PARENTS is non-nil, ARGLIST must be nil."
3816 (cl-callf (lambda (x) (delq declares x)) decls))) 3816 (cl-callf (lambda (x) (delq declares x)) decls)))
3817 (and parents arglist 3817 (and parents arglist
3818 (error "Parents specified, but arglist not empty")) 3818 (error "Parents specified, but arglist not empty"))
3819 `(eval-and-compile ;;cl-eval-when (compile load eval) 3819 `(eval-and-compile
3820 ;; FIXME: Where should `cl--type-deftype' go? Currently, code 3820 (cl--define-derived-type ',name ',parents ',arglist ,docstring)
3821 ;; using `cl-deftype' can use (eval-when-compile (require
3822 ;; 'cl-lib)), so `cl--type-deftype' needs to go either to
3823 ;; `cl-preloaded.el' or it should be autoloaded even when
3824 ;; `cl-lib' is not loaded.
3825 (cl--type-deftype ',name ',parents ',arglist ,docstring)
3826 (define-symbol-prop ',name 'cl-deftype-handler 3821 (define-symbol-prop ',name 'cl-deftype-handler
3827 (cl-function 3822 (cl-function
3828 (lambda (&cl-defs ('*) ,@arglist) 3823 (lambda (&cl-defs ('*) ,@arglist)
3829 ,@decls 3824 ,@decls
3830 ,@forms)))))) 3825 ,@forms))))))
3831 3826
3832(static-if (not (fboundp 'cl--type-deftype)) 3827(static-if (not (fboundp 'cl--define-derived-type))
3833 nil ;; Can't define it yet! 3828 nil ;; Can't define it yet!
3834 (cl-deftype extended-char () '(and character (not base-char)))) 3829 (cl-deftype extended-char () '(and character (not base-char))))
3835 3830
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el
index 0447191bbc7..7dac0519681 100644
--- a/lisp/emacs-lisp/cl-preloaded.el
+++ b/lisp/emacs-lisp/cl-preloaded.el
@@ -467,18 +467,18 @@ The fields are used as follows:
467 467
468;;;; Support for `cl-deftype'. 468;;;; Support for `cl-deftype'.
469 469
470(defvar cl--type-list nil 470(defvar cl--derived-type-list nil
471 "Precedence list of the defined cl-types.") 471 "Precedence list of the defined cl-types.")
472 472
473;; FIXME: The `cl-deftype-handler' property should arguably be turned 473;; FIXME: The `cl-deftype-handler' property should arguably be turned
474;; into a field of this struct (but it has performance and 474;; into a field of this struct (but it has performance and
475;; compatibility implications, so let's not make that change for now). 475;; compatibility implications, so let's not make that change for now).
476(cl-defstruct 476(cl-defstruct
477 (cl-type-class 477 (cl-derived-type-class
478 (:include cl--class) 478 (:include cl--class)
479 (:noinline t) 479 (:noinline t)
480 (:constructor nil) 480 (:constructor nil)
481 (:constructor cl--type-class-make 481 (:constructor cl--derived-type-class-make
482 (name 482 (name
483 docstring 483 docstring
484 parent-types 484 parent-types
@@ -489,15 +489,15 @@ The fields are used as follows:
489 (error "Unknown type: %S" type))) 489 (error "Unknown type: %S" type)))
490 parent-types)))) 490 parent-types))))
491 (:copier nil)) 491 (:copier nil))
492 "Type descriptors for types defined by `cl-deftype'.") 492 "Type descriptors for derived types, i.e. defined by `cl-deftype'.")
493 493
494(defun cl--type-deftype (name parents arglist &optional docstring) 494(defun cl--define-derived-type (name parents arglist &optional docstring)
495 "Register cl-type with NAME for method dispatching. 495 "Register derived type with NAME for method dispatching.
496PARENTS is a list of types NAME is a subtype of, or nil. 496PARENTS is a list of types NAME is a subtype of, or nil.
497DOCSTRING is an optional documentation string." 497DOCSTRING is an optional documentation string."
498 (let* ((class (cl--find-class name))) 498 (let* ((class (cl--find-class name)))
499 (when class 499 (when class
500 (or (cl-type-class-p class) 500 (or (cl-derived-type-class-p class)
501 ;; FIXME: We have some uses `cl-deftype' in Emacs that 501 ;; FIXME: We have some uses `cl-deftype' in Emacs that
502 ;; "complement" another declaration of the same type, 502 ;; "complement" another declaration of the same type,
503 ;; so maybe we should turn this into a warning (and 503 ;; so maybe we should turn this into a warning (and
@@ -505,11 +505,11 @@ DOCSTRING is an optional documentation string."
505 (error "Type in another class: %S" (type-of class)))) 505 (error "Type in another class: %S" (type-of class))))
506 ;; Setup a type descriptor for NAME. 506 ;; Setup a type descriptor for NAME.
507 (setf (cl--find-class name) 507 (setf (cl--find-class name)
508 (cl--type-class-make name docstring parents)) 508 (cl--derived-type-class-make name docstring parents))
509 ;; Record new type. The constructor of the class 509 ;; Record new type. The constructor of the class
510 ;; `cl-type-class' already ensures that parent types must be 510 ;; `cl-type-class' already ensures that parent types must be
511 ;; defined before their "child" types (i.e. already added to 511 ;; defined before their "child" types (i.e. already added to
512 ;; the `cl--type-list' for types defined with `cl-deftype'). 512 ;; the `cl--derived-type-list' for types defined with `cl-deftype').
513 ;; So it is enough to simply push a new type at the beginning 513 ;; So it is enough to simply push a new type at the beginning
514 ;; of the list. 514 ;; of the list.
515 ;; Redefinition is more complicated, because child types may 515 ;; Redefinition is more complicated, because child types may
@@ -524,11 +524,11 @@ DOCSTRING is an optional documentation string."
524 ;; `parents` slots point to the old class object. That's a 524 ;; `parents` slots point to the old class object. That's a
525 ;; problem that affects all types and that we don't really try 525 ;; problem that affects all types and that we don't really try
526 ;; to solve currently. 526 ;; to solve currently.
527 (or (memq name cl--type-list) 527 (or (memq name cl--derived-type-list)
528 ;; Exclude types that can't be used without arguments. 528 ;; Exclude types that can't be used without arguments.
529 ;; They'd signal errors in `cl-types-of'! 529 ;; They'd signal errors in `cl-types-of'!
530 (not (memq (car arglist) '(nil &rest &optional &keys))) 530 (not (memq (car arglist) '(nil &rest &optional &keys)))
531 (push name cl--type-list)))) 531 (push name cl--derived-type-list))))
532 532
533;; Make sure functions defined with cl-defsubst can be inlined even in 533;; Make sure functions defined with cl-defsubst can be inlined even in
534;; packages which do not require CL. We don't put an autoload cookie 534;; packages which do not require CL. We don't put an autoload cookie