(apply #'call-next-method generic-function initargs)))
||#
\f
-;;; These three are scheduled for demolition.
-
-(defmethod remove-named-method (generic-function-name argument-specifiers
- &optional extra)
- (let ((generic-function ())
- (method ()))
- (cond ((or (null (fboundp generic-function-name))
- (not (generic-function-p
- (setq generic-function
- (fdefinition generic-function-name)))))
- (error "~S does not name a generic function."
- generic-function-name))
- ((null (setq method (get-method generic-function
- extra
- (parse-specializers
- argument-specifiers)
- nil)))
- (error "There is no method for the generic function ~S~%~
- which matches the ARGUMENT-SPECIFIERS ~S."
- generic-function
- argument-specifiers))
- (t
- (remove-method generic-function method)))))
-
+;;; These two are scheduled for demolition.
(defun real-add-named-method (generic-function-name
qualifiers
specializers
:specializers specs
:lambda-list lambda-list
other-initargs)))
- (add-method generic-function new)))
+ (add-method generic-function new)
+ new))
+
+(define-condition find-method-length-mismatch
+ (reference-condition simple-error)
+ ()
+ (:default-initargs :references (list '(:ansi-cl :function find-method))))
(defun real-get-method (generic-function qualifiers specializers
- &optional (errorp t))
- (let ((hit
- (dolist (method (generic-function-methods generic-function))
- (let ((mspecializers (method-specializers method)))
- (when (and (equal qualifiers (method-qualifiers method))
- (= (length specializers) (length mspecializers))
- (every #'same-specializer-p specializers
- (method-specializers method)))
- (return method))))))
- (cond (hit hit)
- ((null errorp) nil)
- (t
- (error "no method on ~S with qualifiers ~:S and specializers ~:S"
- generic-function qualifiers specializers)))))
-\f
+ &optional (errorp t)
+ always-check-specializers)
+ (let ((lspec (length specializers))
+ (methods (generic-function-methods generic-function)))
+ (when (or methods always-check-specializers)
+ (let ((nreq (length (arg-info-metatypes (gf-arg-info
+ generic-function)))))
+ ;; Since we internally bypass FIND-METHOD by using GET-METHOD
+ ;; instead we need to to this here or users may get hit by a
+ ;; failed AVER instead of a sensible error message.
+ (when (/= lspec nreq)
+ (error
+ 'find-method-length-mismatch
+ :format-control
+ "~@<The generic function ~S takes ~D required argument~:P; ~
+ was asked to find a method with specializers ~S~@:>"
+ :format-arguments (list generic-function nreq specializers)))))
+ (let ((hit
+ (dolist (method methods)
+ (let ((mspecializers (method-specializers method)))
+ (aver (= lspec (length mspecializers)))
+ (when (and (equal qualifiers (method-qualifiers method))
+ (every #'same-specializer-p specializers
+ (method-specializers method)))
+ (return method))))))
+ (cond (hit hit)
+ ((null errorp) nil)
+ (t
+ (error "~@<There is no method on ~S with ~
+ ~:[no qualifiers~;~:*qualifiers ~S~] ~
+ and specializers ~S.~@:>"
+ generic-function qualifiers specializers))))))
+
(defmethod find-method ((generic-function standard-generic-function)
qualifiers specializers &optional (errorp t))
- (real-get-method generic-function qualifiers
- (parse-specializers specializers) errorp))
+ ;; ANSI about FIND-METHOD: "The specializers argument contains the
+ ;; parameter specializers for the method. It must correspond in
+ ;; length to the number of required arguments of the generic
+ ;; function, or an error is signaled."
+ ;;
+ ;; This error checking is done by REAL-GET-METHOD.
+ (real-get-method generic-function
+ qualifiers
+ (parse-specializers specializers)
+ errorp
+ t))
\f
;;; Compute various information about a generic-function's arglist by looking
;;; at the argument lists of the methods. The hair for trying not to use
(defun make-discriminating-function-arglist (number-required-arguments restp)
(nconc (let ((args nil))
(dotimes (i number-required-arguments)
- (push (intern (format nil "Discriminating Function Arg ~D" i))
+ (push (format-symbol *package* ;; ! is this right?
+ "Discriminating Function Arg ~D"
+ i)
args))
(nreverse args))
(when restp
- `(&rest ,(intern "Discriminating Function &rest Arg")))))
+ `(&rest ,(format-symbol *package*
+ "Discriminating Function &rest Arg")))))
\f
(defmethod generic-function-argument-precedence-order
((gf standard-generic-function))
(defmethod initialize-instance :after ((gf standard-generic-function)
&key (lambda-list nil lambda-list-p)
argument-precedence-order)
- (with-slots (arg-info)
- gf
+ (with-slots (arg-info) gf
(if lambda-list-p
(set-arg-info gf
:lambda-list lambda-list
(when (arg-info-valid-p arg-info)
(update-dfun gf))))
-(defmethod reinitialize-instance :after ((gf standard-generic-function)
- &rest args
- &key (lambda-list nil lambda-list-p)
- (argument-precedence-order
- nil argument-precedence-order-p))
- (with-slots (arg-info)
- gf
- (if lambda-list-p
- (if argument-precedence-order-p
- (set-arg-info gf
- :lambda-list lambda-list
- :argument-precedence-order argument-precedence-order)
- (set-arg-info gf
- :lambda-list lambda-list))
- (set-arg-info gf))
- (when (and (arg-info-valid-p arg-info)
- args
- (or lambda-list-p (cddr args)))
- (update-dfun gf))))
+(defmethod reinitialize-instance :around
+ ((gf standard-generic-function) &rest args &key
+ (lambda-list nil lambda-list-p) (argument-precedence-order nil apo-p))
+ (let ((old-mc (generic-function-method-combination gf)))
+ (prog1 (call-next-method)
+ ;; KLUDGE: EQ is too strong a test.
+ (unless (eq old-mc (generic-function-method-combination gf))
+ (flush-effective-method-cache gf))
+ (cond
+ ((and lambda-list-p apo-p)
+ (set-arg-info gf
+ :lambda-list lambda-list
+ :argument-precedence-order argument-precedence-order))
+ (lambda-list-p (set-arg-info gf :lambda-list lambda-list))
+ (t (set-arg-info gf)))
+ (when (and (arg-info-valid-p (gf-arg-info gf))
+ (not (null args))
+ (or lambda-list-p (cddr args)))
+ (update-dfun gf)))))
(declaim (special *lazy-dfun-compute-p*))
(defun real-add-method (generic-function method &optional skip-dfun-update-p)
(when (method-generic-function method)
- (error "The method ~S is already part of the generic~@
- function ~S. It can't be added to another generic~@
- function until it is removed from the first one."
+ (error "~@<The method ~S is already part of the generic ~
+ function ~S; it can't be added to another generic ~
+ function until it is removed from the first one.~@:>"
method (method-generic-function method)))
(flet ((similar-lambda-lists-p (method-a method-b)
(multiple-value-bind (a-nreq a-nopt a-keyp a-restp)
(setq remove-again-p nil))
(when remove-again-p
(remove-method generic-function method))))
+
+ ;; KLUDGE II: ANSI saith that it is not an error to add a
+ ;; method with invalid qualifiers to a generic function of the
+ ;; wrong kind; it's only an error at generic function
+ ;; invocation time; I dunno what the rationale was, and it
+ ;; sucks. Nevertheless, it's probably a programmer error, so
+ ;; let's warn anyway. -- CSR, 2003-08-20
+ (let ((mc (generic-function-method-combination generic-functioN)))
+ (cond
+ ((eq mc *standard-method-combination*)
+ (when (and qualifiers
+ (or (cdr qualifiers)
+ (not (memq (car qualifiers)
+ '(:around :before :after)))))
+ (warn "~@<Invalid qualifiers for standard method combination ~
+ in method ~S:~2I~_~S.~@:>"
+ method qualifiers)))
+ ((short-method-combination-p mc)
+ (let ((mc-name (method-combination-type mc)))
+ (when (or (null qualifiers)
+ (cdr qualifiers)
+ (and (neq (car qualifiers) :around)
+ (neq (car qualifiers) mc-name)))
+ (warn "~@<Invalid qualifiers for ~S method combination ~
+ in method ~S:~2I~_~S.~@:>"
+ mc-name method qualifiers))))))
+
(unless skip-dfun-update-p
(update-ctors 'add-method
:generic-function generic-function
:method method)
(update-dfun generic-function))
- method)))
+ generic-function)))
(defun real-remove-method (generic-function method)
(when (eq generic-function (method-generic-function method))
(let ((types (mapcar #'class-eq-type classes)))
(multiple-value-bind (methods all-applicable-and-sorted-p)
(compute-applicable-methods-using-types gf types)
- (function-funcall (get-secondary-dispatch-function1
- gf methods types nil t all-applicable-and-sorted-p)
- nil (mapcar #'class-wrapper classes)))))
+ (let ((generator (get-secondary-dispatch-function1
+ gf methods types nil t all-applicable-and-sorted-p)))
+ (make-callable gf methods generator
+ nil (mapcar #'class-wrapper classes))))))
(defun value-for-caching (gf classes)
(let ((methods (compute-applicable-methods-using-types
(loop (when (atom x) (return (eq x y)))
(when (atom y) (return nil))
(unless (eq (car x) (car y)) (return nil))
- (setq x (cdr x) y (cdr y))))
+ (setq x (cdr x)
+ y (cdr y))))
(defvar *std-cam-methods* nil)
(set-dfun gf dfun cache info) ; lest the cache be freed twice
(update-dfun gf dfun cache info))))))
\f
+(defmethod (setf class-name) :before (new-value (class class))
+ (let ((classoid (find-classoid (class-name class))))
+ (setf (classoid-name classoid) new-value)))
+\f
(defmethod function-keywords ((method standard-method))
(multiple-value-bind (nreq nopt keysp restp allow-other-keys-p keywords)
(analyze-lambda-list (if (consp method)