aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2015-01-26 09:04:55 -0500
committerStefan Monnier2015-01-26 09:04:55 -0500
commit4cdde9196fb4fafb00b0c51b908fd605274147bd (patch)
tree34b825a588203225f126027cff47f95772af2a28
parent242354a23acf214ad06d4e3e7e5f5580c8b21d4a (diff)
downloademacs-4cdde9196fb4fafb00b0c51b908fd605274147bd.tar.gz
emacs-4cdde9196fb4fafb00b0c51b908fd605274147bd.zip
* lisp/emacs-lisp/cl-generic.el: Add a method-combination hook.
(cl-generic-method-combination-function): New var. (cl--generic-lambda): Remove `with-cnm' arg. (cl-defmethod): Change accordingly. (cl-generic-define-method): Don't check qualifiers validity. Preserve all qualifiers in `method-table'. (cl-generic-call-method): New function. (cl--generic-nest): Remove (morph into cl-generic-call-method). (cl--generic-build-combined-method): Adjust to new format of method-table and use cl-generic-method-combination-function. (cl--generic-standard-method-combination): New function, extracted from cl--generic-build-combined-method. (cl--generic-cnm-sample): Adjust to new format of method-table. * lisp/emacs-lisp/eieio-compat.el (eieio--defmethod): Use () qualifiers instead of :primary. * lisp/emacs-lisp/eieio-datadebug.el (eieio-debug-methodinvoke): Remove obsolete function. * test/automated/cl-generic-tests.el (cl-generic-test-11-next-method-p): New test.
-rw-r--r--lisp/ChangeLog22
-rw-r--r--lisp/emacs-lisp/cl-generic.el205
-rw-r--r--lisp/emacs-lisp/eieio-compat.el6
-rw-r--r--lisp/emacs-lisp/eieio-datadebug.el16
-rw-r--r--test/ChangeLog5
-rw-r--r--test/automated/cl-generic-tests.el8
6 files changed, 155 insertions, 107 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 8af0ec46cad..0bdf4e275fa 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,25 @@
12015-01-26 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * emacs-lisp/cl-generic.el: Add a method-combination hook.
4 (cl-generic-method-combination-function): New var.
5 (cl--generic-lambda): Remove `with-cnm' arg.
6 (cl-defmethod): Change accordingly.
7 (cl-generic-define-method): Don't check qualifiers validity.
8 Preserve all qualifiers in `method-table'.
9 (cl-generic-call-method): New function.
10 (cl--generic-nest): Remove (morph into cl-generic-call-method).
11 (cl--generic-build-combined-method): Adjust to new format of method-table
12 and use cl-generic-method-combination-function.
13 (cl--generic-standard-method-combination): New function, extracted from
14 cl--generic-build-combined-method.
15 (cl--generic-cnm-sample): Adjust to new format of method-table.
16
17 * emacs-lisp/eieio-compat.el (eieio--defmethod): Use () qualifiers
18 instead of :primary.
19
20 * emacs-lisp/eieio-datadebug.el (eieio-debug-methodinvoke):
21 Remove obsolete function.
22
12015-01-26 Lars Ingebrigtsen <larsi@gnus.org> 232015-01-26 Lars Ingebrigtsen <larsi@gnus.org>
2 24
3 * net/shr.el (shr-make-table-1): Fix colspan typo. 25 * net/shr.el (shr-make-table-1): Fix colspan typo.
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 02a43514019..4245959c8a4 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -30,7 +30,9 @@
30;; CLOS's define-method-combination is IMO overly complicated, and it suffers 30;; CLOS's define-method-combination is IMO overly complicated, and it suffers
31;; from a significant problem: the method-combination code returns a sexp 31;; from a significant problem: the method-combination code returns a sexp
32;; that needs to be `eval'uated or compiled. IOW it requires run-time 32;; that needs to be `eval'uated or compiled. IOW it requires run-time
33;; code generation. 33;; code generation. Given how rarely method-combinations are used,
34;; I just provided a cl-generic-method-combination-function, which
35;; people can use if they are really desperate for such functionality.
34;; - Method and generic function objects: CLOS defines methods as objects 36;; - Method and generic function objects: CLOS defines methods as objects
35;; (same for generic functions), whereas we don't offer such an abstraction. 37;; (same for generic functions), whereas we don't offer such an abstraction.
36;; - `no-next-method' should receive the "calling method" object, but since we 38;; - `no-next-method' should receive the "calling method" object, but since we
@@ -115,10 +117,10 @@ They should be sorted from most specific to least specific.")
115 ;; The most important dispatch is last in the list (and the least is first). 117 ;; The most important dispatch is last in the list (and the least is first).
116 (dispatches nil :type (list-of (cons natnum (list-of tagcode)))) 118 (dispatches nil :type (list-of (cons natnum (list-of tagcode))))
117 ;; `method-table' is a list of 119 ;; `method-table' is a list of
118 ;; ((SPECIALIZERS . QUALIFIER) USES-CNM . FUNCTION), where 120 ;; ((SPECIALIZERS . QUALIFIERS) USES-CNM . FUNCTION), where
119 ;; USES-CNM is a boolean indicating if FUNCTION calls `cl-call-next-method' 121 ;; USES-CNM is a boolean indicating if FUNCTION calls `cl-call-next-method'
120 ;; (and hence expects an extra argument holding the next-method). 122 ;; (and hence expects an extra argument holding the next-method).
121 (method-table nil :type (list-of (cons (cons (list-of type) keyword) 123 (method-table nil :type (list-of (cons (cons (list-of type) (list-of atom))
122 (cons boolean function))))) 124 (cons boolean function)))))
123 125
124(defmacro cl--generic (name) 126(defmacro cl--generic (name)
@@ -232,7 +234,7 @@ This macro can only be used within the lexical scope of a cl-generic method."
232 (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) 234 (and (memq sexp vars) (not (memq sexp res)) (push sexp res))
233 res)) 235 res))
234 236
235 (defun cl--generic-lambda (args body with-cnm) 237 (defun cl--generic-lambda (args body)
236 "Make the lambda expression for a method with ARGS and BODY." 238 "Make the lambda expression for a method with ARGS and BODY."
237 (let ((plain-args ()) 239 (let ((plain-args ())
238 (specializers nil) 240 (specializers nil)
@@ -255,36 +257,34 @@ This macro can only be used within the lexical scope of a cl-generic method."
255 . ,(lambda () specializers)) 257 . ,(lambda () specializers))
256 macroexpand-all-environment))) 258 macroexpand-all-environment)))
257 (require 'cl-lib) ;Needed to expand `cl-flet' and `cl-function'. 259 (require 'cl-lib) ;Needed to expand `cl-flet' and `cl-function'.
258 (if (not with-cnm) 260 ;; First macroexpand away the cl-function stuff (e.g. &key and
259 (cons nil (macroexpand-all fun macroenv)) 261 ;; destructuring args, `declare' and whatnot).
260 ;; First macroexpand away the cl-function stuff (e.g. &key and 262 (pcase (macroexpand fun macroenv)
261 ;; destructuring args, `declare' and whatnot). 263 (`#'(lambda ,args . ,body)
262 (pcase (macroexpand fun macroenv) 264 (let* ((doc-string (and doc-string (stringp (car body)) (cdr body)
263 (`#'(lambda ,args . ,body) 265 (pop body)))
264 (let* ((doc-string (and doc-string (stringp (car body)) (cdr body) 266 (cnm (make-symbol "cl--cnm"))
265 (pop body))) 267 (nmp (make-symbol "cl--nmp"))
266 (cnm (make-symbol "cl--cnm")) 268 (nbody (macroexpand-all
267 (nmp (make-symbol "cl--nmp")) 269 `(cl-flet ((cl-call-next-method ,cnm)
268 (nbody (macroexpand-all 270 (cl-next-method-p ,nmp))
269 `(cl-flet ((cl-call-next-method ,cnm) 271 ,@body)
270 (cl-next-method-p ,nmp)) 272 macroenv))
271 ,@body) 273 ;; FIXME: Rather than `grep' after the fact, the
272 macroenv)) 274 ;; macroexpansion should directly set some flag when cnm
273 ;; FIXME: Rather than `grep' after the fact, the 275 ;; is used.
274 ;; macroexpansion should directly set some flag when cnm 276 ;; FIXME: Also, optimize the case where call-next-method is
275 ;; is used. 277 ;; only called with explicit arguments.
276 ;; FIXME: Also, optimize the case where call-next-method is 278 (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody)))
277 ;; only called with explicit arguments. 279 (cons (not (not uses-cnm))
278 (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody))) 280 `#'(lambda (,@(if uses-cnm (list cnm)) ,@args)
279 (cons (not (not uses-cnm)) 281 ,@(if doc-string (list doc-string))
280 `#'(lambda (,@(if uses-cnm (list cnm)) ,@args) 282 ,(if (not (memq nmp uses-cnm))
281 ,@(if doc-string (list doc-string)) 283 nbody
282 ,(if (not (memq nmp uses-cnm)) 284 `(let ((,nmp (lambda ()
283 nbody 285 (cl--generic-isnot-nnm-p ,cnm))))
284 `(let ((,nmp (lambda () 286 ,nbody))))))
285 (cl--generic-isnot-nnm-p ,cnm)))) 287 (f (error "Unexpected macroexpansion result: %S" f)))))))
286 ,nbody))))))
287 (f (error "Unexpected macroexpansion result: %S" f))))))))
288 288
289 289
290;;;###autoload 290;;;###autoload
@@ -324,8 +324,7 @@ which case this method will be invoked when the argument is `eql' to VAL.
324 (while (not (listp args)) 324 (while (not (listp args))
325 (push args qualifiers) 325 (push args qualifiers)
326 (setq args (pop body))) 326 (setq args (pop body)))
327 (pcase-let* ((with-cnm (not (memq (car qualifiers) '(:before :after)))) 327 (pcase-let* ((`(,uses-cnm . ,fun) (cl--generic-lambda args body)))
328 (`(,uses-cnm . ,fun) (cl--generic-lambda args body with-cnm)))
329 `(progn 328 `(progn
330 ,(when setfizer 329 ,(when setfizer
331 (setq name (car setfizer)) 330 (setq name (car setfizer))
@@ -347,15 +346,11 @@ which case this method will be invoked when the argument is `eql' to VAL.
347 346
348;;;###autoload 347;;;###autoload
349(defun cl-generic-define-method (name qualifiers args uses-cnm function) 348(defun cl-generic-define-method (name qualifiers args uses-cnm function)
350 (when (> (length qualifiers) 1)
351 (error "We only support a single qualifier per method: %S" qualifiers))
352 (unless (memq (car qualifiers) '(nil :primary :around :after :before))
353 (error "Unsupported qualifier in: %S" qualifiers))
354 (let* ((generic (cl-generic-ensure-function name)) 349 (let* ((generic (cl-generic-ensure-function name))
355 (mandatory (cl--generic-mandatory-args args)) 350 (mandatory (cl--generic-mandatory-args args))
356 (specializers 351 (specializers
357 (mapcar (lambda (arg) (if (consp arg) (cadr arg) t)) mandatory)) 352 (mapcar (lambda (arg) (if (consp arg) (cadr arg) t)) mandatory))
358 (key (cons specializers (or (car qualifiers) ':primary))) 353 (key (cons specializers qualifiers))
359 (mt (cl--generic-method-table generic)) 354 (mt (cl--generic-method-table generic))
360 (me (assoc key mt)) 355 (me (assoc key mt))
361 (dispatches (cl--generic-dispatches generic)) 356 (dispatches (cl--generic-dispatches generic))
@@ -438,22 +433,19 @@ which case this method will be invoked when the argument is `eql' to VAL.
438 (cdr dispatch) (car dispatch)))) 433 (cdr dispatch) (car dispatch))))
439 (funcall dispatcher generic dispatches))))) 434 (funcall dispatcher generic dispatches)))))
440 435
441(defun cl--generic-nest (fun methods) 436(defvar cl-generic-method-combination-function
442 (pcase-dolist (`(,uses-cnm . ,method) methods) 437 #'cl--generic-standard-method-combination
443 (setq fun 438 "Function to build the effective method.
444 (if (not uses-cnm) method 439Called with 2 arguments: NAME and METHOD-ALIST.
445 (let ((next fun)) 440It should return an effective method, i.e. a function that expects the same
446 (lambda (&rest args) 441arguments as the methods, and calls those methods in some appropriate order.
447 (apply method 442NAME is the name (a symbol) of the corresponding generic function.
448 ;; FIXME: This sucks: passing just `next' would 443METHOD-ALIST is a list of elements (QUALIFIERS . METHODS) where
449 ;; be a lot more efficient than the lambda+apply 444QUALIFIERS is a list of qualifiers, and METHODS is a list of the selected
450 ;; quasi-η, but we need this to implement the 445methods for that qualifier list.
451 ;; "if call-next-method is called with no 446The METHODS lists are sorted from most generic first to most specific last.
452 ;; arguments, then use the previous arguments". 447The function can use `cl-generic-call-method' to create functions that call those
453 (lambda (&rest cnm-args) 448methods.")
454 (apply next (or cnm-args args)))
455 args))))))
456 fun)
457 449
458(defvar cl--generic-combined-method-memoization 450(defvar cl--generic-combined-method-memoization
459 (make-hash-table :test #'equal :weakness 'value) 451 (make-hash-table :test #'equal :weakness 'value)
@@ -462,6 +454,22 @@ This is particularly useful when many different tags select the same set
462of methods, since this table then allows us to share a single combined-method 454of methods, since this table then allows us to share a single combined-method
463for all those different tags in the method-cache.") 455for all those different tags in the method-cache.")
464 456
457(defun cl--generic-build-combined-method (generic-name methods)
458 (cl--generic-with-memoization
459 (gethash (cons generic-name methods)
460 cl--generic-combined-method-memoization)
461 (let ((mets-by-qual ()))
462 (dolist (qm methods)
463 (let* ((qualifiers (cdar qm))
464 (x (assoc qualifiers mets-by-qual)))
465 ;; FIXME: sadly, alist-get only uses `assq' and we need `assoc'.
466 ;;(push (cdr qm) (alist-get qualifiers mets-by-qual)))
467 (if x
468 (push (cdr qm) (cdr x))
469 (push (list qualifiers (cdr qm)) mets-by-qual))))
470 (funcall cl-generic-method-combination-function
471 generic-name mets-by-qual))))
472
465(defun cl--generic-no-next-method-function (generic) 473(defun cl--generic-no-next-method-function (generic)
466 (lambda (&rest args) 474 (lambda (&rest args)
467 ;; FIXME: CLOS passes as second arg the "calling method". 475 ;; FIXME: CLOS passes as second arg the "calling method".
@@ -474,42 +482,61 @@ for all those different tags in the method-cache.")
474 ;; it anyway. So we pass nil for now. 482 ;; it anyway. So we pass nil for now.
475 (apply #'cl-no-next-method generic nil args))) 483 (apply #'cl-no-next-method generic nil args)))
476 484
477(defun cl--generic-build-combined-method (generic-name methods) 485(defun cl-generic-call-method (generic-name method &optional fun)
478 (let ((mets-by-qual ())) 486 "Return a function that calls METHOD.
479 (dolist (qm methods) 487FUN is the function that should be called when METHOD calls
480 (push (cdr qm) (alist-get (cdar qm) mets-by-qual))) 488`call-next-method'."
481 (cl--generic-with-memoization 489 (pcase method
482 (gethash (cons generic-name mets-by-qual) 490 (`(nil . ,method) method)
483 cl--generic-combined-method-memoization) 491 (`(,_uses-cnm . ,method)
484 (cond 492 (let ((next (or fun (cl--generic-no-next-method-function generic-name))))
485 ((null mets-by-qual) 493 (lambda (&rest args)
486 (lambda (&rest args) 494 (apply method
487 (apply #'cl-no-applicable-method generic-name args))) 495 ;; FIXME: This sucks: passing just `next' would
488 ((null (alist-get :primary mets-by-qual)) 496 ;; be a lot more efficient than the lambda+apply
489 (lambda (&rest args) 497 ;; quasi-η, but we need this to implement the
490 (apply #'cl-no-primary-method generic-name args))) 498 ;; "if call-next-method is called with no
491 (t 499 ;; arguments, then use the previous arguments".
492 (let* ((fun (cl--generic-no-next-method-function generic-name)) 500 (lambda (&rest cnm-args)
493 ;; We use `cdr' to drop the `uses-cnm' annotations. 501 (apply next (or cnm-args args)))
494 (before 502 args))))))
495 (mapcar #'cdr (reverse (alist-get :before mets-by-qual)))) 503
496 (after (mapcar #'cdr (alist-get :after mets-by-qual)))) 504(defun cl--generic-standard-method-combination (generic-name mets-by-qual)
497 (setq fun (cl--generic-nest fun (alist-get :primary mets-by-qual))) 505 (dolist (x mets-by-qual)
498 (when (or after before) 506 (unless (member (car x) '(() (:after) (:before) (:around)))
499 (let ((next fun)) 507 (error "Unsupported qualifiers in function %S: %S" generic-name (car x))))
500 (setq fun (lambda (&rest args) 508 (cond
501 (dolist (bf before) 509 ((null mets-by-qual)
502 (apply bf args)) 510 (lambda (&rest args)
503 (prog1 511 (apply #'cl-no-applicable-method generic-name args)))
504 (apply next args) 512 ((null (alist-get nil mets-by-qual))
505 (dolist (af after) 513 (lambda (&rest args)
506 (apply af args))))))) 514 (apply #'cl-no-primary-method generic-name args)))
507 (cl--generic-nest fun (alist-get :around mets-by-qual)))))))) 515 (t
516 (let* ((fun nil)
517 (ab-call (lambda (m) (cl-generic-call-method generic-name m)))
518 (before
519 (mapcar ab-call (reverse (cdr (assoc '(:before) mets-by-qual)))))
520 (after (mapcar ab-call (cdr (assoc '(:after) mets-by-qual)))))
521 (dolist (method (cdr (assoc nil mets-by-qual)))
522 (setq fun (cl-generic-call-method generic-name method fun)))
523 (when (or after before)
524 (let ((next fun))
525 (setq fun (lambda (&rest args)
526 (dolist (bf before)
527 (apply bf args))
528 (prog1
529 (apply next args)
530 (dolist (af after)
531 (apply af args)))))))
532 (dolist (method (cdr (assoc '(:around) mets-by-qual)))
533 (setq fun (cl-generic-call-method generic-name method fun)))
534 fun))))
508 535
509(defconst cl--generic-nnm-sample (cl--generic-no-next-method-function 'dummy)) 536(defconst cl--generic-nnm-sample (cl--generic-no-next-method-function 'dummy))
510(defconst cl--generic-cnm-sample 537(defconst cl--generic-cnm-sample
511 (funcall (cl--generic-build-combined-method 538 (funcall (cl--generic-build-combined-method
512 nil `(((specializer . :primary) t . ,#'identity))))) 539 nil `(((specializer . nil) t . ,#'identity)))))
513 540
514(defun cl--generic-isnot-nnm-p (cnm) 541(defun cl--generic-isnot-nnm-p (cnm)
515 "Return non-nil if CNM is the function that calls `cl-no-next-method'." 542 "Return non-nil if CNM is the function that calls `cl-no-next-method'."
diff --git a/lisp/emacs-lisp/eieio-compat.el b/lisp/emacs-lisp/eieio-compat.el
index c2dabf7f446..30bb5cee994 100644
--- a/lisp/emacs-lisp/eieio-compat.el
+++ b/lisp/emacs-lisp/eieio-compat.el
@@ -181,7 +181,8 @@ Summary:
181 (lambda (generic arg &rest args) (apply code arg generic args))) 181 (lambda (generic arg &rest args) (apply code arg generic args)))
182 (_ code)))) 182 (_ code))))
183 (cl-generic-define-method 183 (cl-generic-define-method
184 method (if kind (list kind)) specializers uses-cnm 184 method (unless (memq kind '(nil :primary)) (list kind))
185 specializers uses-cnm
185 (if uses-cnm 186 (if uses-cnm
186 (let* ((docstring (documentation code 'raw)) 187 (let* ((docstring (documentation code 'raw))
187 (args (help-function-arglist code 'preserve-names)) 188 (args (help-function-arglist code 'preserve-names))
@@ -201,10 +202,11 @@ Summary:
201 ;; applicable but only of the before/after kind. So if we add a :before 202 ;; applicable but only of the before/after kind. So if we add a :before
202 ;; or :after, make sure there's a matching dummy primary. 203 ;; or :after, make sure there's a matching dummy primary.
203 (when (and (memq kind '(:before :after)) 204 (when (and (memq kind '(:before :after))
205 ;; FIXME: Use `cl-find-method'?
204 (not (assoc (cons (mapcar (lambda (arg) 206 (not (assoc (cons (mapcar (lambda (arg)
205 (if (consp arg) (nth 1 arg) t)) 207 (if (consp arg) (nth 1 arg) t))
206 specializers) 208 specializers)
207 :primary) 209 nil)
208 (cl--generic-method-table (cl--generic method))))) 210 (cl--generic-method-table (cl--generic method)))))
209 (cl-generic-define-method method () specializers t 211 (cl-generic-define-method method () specializers t
210 (lambda (cnm &rest args) 212 (lambda (cnm &rest args)
diff --git a/lisp/emacs-lisp/eieio-datadebug.el b/lisp/emacs-lisp/eieio-datadebug.el
index 6534bd0fecf..119f7cce038 100644
--- a/lisp/emacs-lisp/eieio-datadebug.el
+++ b/lisp/emacs-lisp/eieio-datadebug.el
@@ -129,22 +129,6 @@ PREBUTTONTEXT is some text between PREFIX and the object button."
129 (data-debug-new-buffer (format "*%s DDEBUG*" (eieio-object-name obj))) 129 (data-debug-new-buffer (format "*%s DDEBUG*" (eieio-object-name obj)))
130 (data-debug-insert-object-slots obj "]")) 130 (data-debug-insert-object-slots obj "]"))
131 131
132;;; DEBUG FUNCTIONS
133;;
134(defun eieio-debug-methodinvoke (method class)
135 "Show the method invocation order for METHOD with CLASS object."
136 (interactive "aMethod: \nXClass Expression: ")
137 (let* ((eieio-pre-method-execution-functions
138 (lambda (l) (throw 'moose l) ))
139 (data
140 (catch 'moose (eieio--generic-call
141 method (list class))))
142 (_buf (data-debug-new-buffer "*Method Invocation*"))
143 (data2 (mapcar (lambda (sym)
144 (symbol-function (car sym)))
145 data)))
146 (data-debug-insert-thing data2 ">" "")))
147
148(provide 'eieio-datadebug) 132(provide 'eieio-datadebug)
149 133
150;;; eieio-datadebug.el ends here 134;;; eieio-datadebug.el ends here
diff --git a/test/ChangeLog b/test/ChangeLog
index d8cd36790f2..9a31da45416 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,8 @@
12015-01-26 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * automated/cl-generic-tests.el (cl-generic-test-11-next-method-p):
4 New test.
5
12015-01-25 Paul Eggert <eggert@cs.ucla.edu> 62015-01-25 Paul Eggert <eggert@cs.ucla.edu>
2 7
3 * indent/shell.sh (bar): Use '[ $# -eq 0 ]', not '[ $# == 0 ]'. 8 * indent/shell.sh (bar): Use '[ $# -eq 0 ]', not '[ $# == 0 ]'.
diff --git a/test/automated/cl-generic-tests.el b/test/automated/cl-generic-tests.el
index bc9a1ece423..5b3a9fdc2a1 100644
--- a/test/automated/cl-generic-tests.el
+++ b/test/automated/cl-generic-tests.el
@@ -171,5 +171,13 @@
171 (should (equal (cl--generic-1 'a 'b) '(a b))) 171 (should (equal (cl--generic-1 'a 'b) '(a b)))
172 (should (equal (cl--generic-1 1 2) '("integer" 2 1)))) 172 (should (equal (cl--generic-1 1 2) '("integer" 2 1))))
173 173
174(ert-deftest cl-generic-test-11-next-method-p ()
175 (cl-defgeneric cl--generic-1 (x y))
176 (cl-defmethod cl--generic-1 ((x t) y)
177 (list x y (cl-next-method-p)))
178 (cl-defmethod cl--generic-1 ((_x (eql 4)) _y)
179 (cl-list* "quatre" (cl-next-method-p) (cl-call-next-method)))
180 (should (equal (cl--generic-1 4 5) '("quatre" t 4 5 nil))))
181
174(provide 'cl-generic-tests) 182(provide 'cl-generic-tests)
175;;; cl-generic-tests.el ends here 183;;; cl-generic-tests.el ends here