aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2026-01-09 14:17:09 -0500
committerStefan Monnier2026-01-09 14:18:31 -0500
commit6c818936e00bf24201dbfa8916cd91aca24f84c9 (patch)
tree63d7a78b562cf8e90f163b3e0ae225121471bac5
parente07e14a7be4d97c5e1623d34055c1ee6fe6d9e02 (diff)
downloademacs-6c818936e00bf24201dbfa8916cd91aca24f84c9.tar.gz
emacs-6c818936e00bf24201dbfa8916cd91aca24f84c9.zip
(cl--generic-build-combined-method): Fix lingering error (bug#80154)
The cycle detection could occasionally leave some lingering cycle marker leading to bogus errors. While we're here, streamline the code, to eliminate an unneeded signal+condition-case. * lisp/emacs-lisp/cl-generic.el (cl--generic-build-combined-method): Delete error. (cl--generic-build-combined-method): Rewrite.
-rw-r--r--lisp/emacs-lisp/cl-generic.el59
1 files changed, 31 insertions, 28 deletions
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 405500c0987..ea73ce766f5 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -855,33 +855,32 @@ This is particularly useful when many different tags select the same set
855of methods, since this table then allows us to share a single combined-method 855of methods, since this table then allows us to share a single combined-method
856for all those different tags in the method-cache.") 856for all those different tags in the method-cache.")
857 857
858(define-error 'cl--generic-cyclic-definition "Cyclic definition")
859
860(defun cl--generic-build-combined-method (generic methods) 858(defun cl--generic-build-combined-method (generic methods)
861 (if (null methods) 859 ;; Since `cl-generic-combine-methods' is itself a generic function,
862 ;; Special case needed to fix a circularity during bootstrap. 860 ;; there is a chicken and egg problem when computing a combined
863 (cl--generic-standard-method-combination generic methods) 861 ;; method for `cl-generic-combine-methods'.
864 (let ((f 862 ;; We break such infinite recursion by detecting it and falling
865 (with-memoization 863 ;; back to `cl--generic-standard-method-combination' when it happens.
866 ;; FIXME: Since the fields of `generic' are modified, this 864 ;; FIXME: Since the fields of `generic' are modified, the
867 ;; hash-table won't work right, because the hashes will change! 865 ;; `cl--generic-combined-method-memoization' hash-table won't work
868 ;; It's not terribly serious, but reduces the effectiveness of 866 ;; right, because the hashes will change! It's not terribly serious,
869 ;; the table. 867 ;; but reduces the effectiveness of the table.
870 (gethash (cons generic methods) 868 (let ((key (cons generic methods)))
871 cl--generic-combined-method-memoization) 869 (pcase (gethash key cl--generic-combined-method-memoization)
872 (puthash (cons generic methods) :cl--generic--under-construction 870 (:cl--generic--under-construction
873 cl--generic-combined-method-memoization) 871 ;; Fallback to the standard method combination.
874 (condition-case nil 872 (setf (gethash key cl--generic-combined-method-memoization)
875 (cl-generic-combine-methods generic methods) 873 (cl--generic-standard-method-combination generic methods)))
876 ;; Special case needed to fix a circularity during bootstrap. 874 ('nil
877 (cl--generic-cyclic-definition 875 (setf (gethash key cl--generic-combined-method-memoization)
878 (cl--generic-standard-method-combination generic methods)))))) 876 :cl--generic--under-construction)
879 (if (eq f :cl--generic--under-construction) 877 (let ((f nil))
880 (signal 'cl--generic-cyclic-definition 878 (unwind-protect
881 (list (cl--generic-name generic))) 879 (setq f (cl-generic-combine-methods generic methods))
882 f)))) 880 (setf (gethash key cl--generic-combined-method-memoization) f))))
883 881 (f f))))
884(oclosure-define (cl--generic-nnm) 882
883(oclosure-define cl--generic-nnm
885 "Special type for `call-next-method's that just call `no-next-method'.") 884 "Special type for `call-next-method's that just call `no-next-method'.")
886 885
887(defun cl-generic-call-method (generic method &optional fun) 886(defun cl-generic-call-method (generic method &optional fun)
@@ -986,6 +985,10 @@ FUN is the function that should be called when METHOD calls
986 (setq methods (nreverse (mapcar #'cdr (sort methods #'car-less-than-car)))) 985 (setq methods (nreverse (mapcar #'cdr (sort methods #'car-less-than-car))))
987 (cl--generic-make-next-function generic dispatches-left methods))) 986 (cl--generic-make-next-function generic dispatches-left methods)))
988 987
988(unless (ignore-errors (cl-generic-generalizers t))
989 ;; Temporary definition to let the next defgenerics succeed.
990 (fset 'cl-generic-combine-methods #'cl--generic-standard-method-combination))
991
989(cl-defgeneric cl-generic-generalizers (specializer) 992(cl-defgeneric cl-generic-generalizers (specializer)
990 "Return a list of generalizers for a given SPECIALIZER. 993 "Return a list of generalizers for a given SPECIALIZER.
991To each kind of `specializer', corresponds a `generalizer' which describes 994To each kind of `specializer', corresponds a `generalizer' which describes
@@ -1002,11 +1005,11 @@ The code which extracts the tag should be as fast as possible.
1002The tags should be chosen according to the following rules: 1005The tags should be chosen according to the following rules:
1003- The tags should not be too specific: similar objects which match the 1006- The tags should not be too specific: similar objects which match the
1004 same list of specializers should ideally use the same (`eql') tag. 1007 same list of specializers should ideally use the same (`eql') tag.
1005 This insures that the cached computation of the applicable 1008 This ensures that the cached computation of the applicable
1006 methods for one object can be reused for other objects. 1009 methods for one object can be reused for other objects.
1007- Corollary: objects which don't match any of the relevant specializers 1010- Corollary: objects which don't match any of the relevant specializers
1008 should ideally all use the same tag (typically nil). 1011 should ideally all use the same tag (typically nil).
1009 This insures that this cache does not grow unnecessarily large. 1012 This ensures that this cache does not grow unnecessarily large.
1010- Two different generalizers G1 and G2 should not use the same tag 1013- Two different generalizers G1 and G2 should not use the same tag
1011 unless they use it for the same set of objects. IOW, if G1.tag(X1) = 1014 unless they use it for the same set of objects. IOW, if G1.tag(X1) =
1012 G2.tag(X2) then G1.tag(X1) = G2.tag(X1) = G1.tag(X2) = G2.tag(X2). 1015 G2.tag(X2) then G1.tag(X1) = G2.tag(X1) = G1.tag(X2) = G2.tag(X2).