X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fmethods.lisp;h=c395c7bab7f35cdffbc0683b1cca7a9cdf48ae98;hb=09702467ab16baab34dc209606d9d07af38eaedd;hp=9f181f77c803447d1b76e3f5fe5a28367cd772a0;hpb=3a2e34d8ed1293f2cecb5c2c6ea359b622e3f4f8;p=sbcl.git diff --git a/src/pcl/methods.lisp b/src/pcl/methods.lisp index 9f181f7..c395c7b 100644 --- a/src/pcl/methods.lisp +++ b/src/pcl/methods.lisp @@ -23,29 +23,13 @@ (in-package "SB-PCL") - ;;; methods ;;; ;;; Methods themselves are simple inanimate objects. Most properties of ;;; methods are immutable, methods cannot be reinitialized. The following ;;; properties of methods can be changed: ;;; METHOD-GENERIC-FUNCTION -;;; METHOD-FUNCTION ?? - -(defmethod method-function ((method standard-method)) - (or (slot-value method 'function) - (let ((fmf (slot-value method 'fast-function))) - (unless fmf ; The :BEFORE SHARED-INITIALIZE method prevents this. - (error "~S doesn't seem to have a METHOD-FUNCTION." method)) - (setf (slot-value method 'function) - (method-function-from-fast-function fmf))))) - -(defmethod accessor-method-class ((method standard-accessor-method)) - (car (slot-value method 'specializers))) - -(defmethod accessor-method-class ((method standard-writer-method)) - (cadr (slot-value method 'specializers))) - + ;;; initialization ;;; ;;; Error checking is done in before methods. Because of the simplicity of @@ -53,134 +37,125 @@ ;;; ;;; Methods are not reinitializable. -(defmethod reinitialize-instance ((method standard-method) &rest initargs) - (declare (ignore initargs)) - (error "An attempt was made to reinitialize the method ~S.~%~ - Method objects cannot be reinitialized." - method)) - -(defmethod legal-documentation-p ((object standard-method) x) - (if (or (null x) (stringp x)) - t - "a string or NULL")) - -(defmethod legal-lambda-list-p ((object standard-method) x) - (declare (ignore x)) - t) +(define-condition metaobject-initialization-violation + (reference-condition simple-error) + ()) + +(macrolet ((def (name args control) + `(defmethod ,name ,args + (declare (ignore initargs)) + (error 'metaobject-initialization-violation + :format-control ,(format nil "~@<~A~@:>" control) + :format-arguments (list ',name) + :references (list '(:amop :initialization method)))))) + (def reinitialize-instance ((method method) &rest initargs) + "Method objects cannot be redefined by ~S.") + (def change-class ((method method) new &rest initargs) + "Method objects cannot be redefined by ~S.") + ;; NEW being a subclass of method is dealt with in the general + ;; method of CHANGE-CLASS + (def update-instance-for-redefined-class ((method method) added discarded + plist &rest initargs) + "No behaviour specified for ~S on method objects.") + (def update-instance-for-different-class (old (new method) &rest initargs) + "No behaviour specified for ~S on method objects.") + (def update-instance-for-different-class ((old method) new &rest initargs) + "No behaviour specified for ~S on method objects.")) + +(define-condition invalid-method-initarg (simple-program-error) + ((method :initarg :method :reader invalid-method-initarg-method)) + (:report + (lambda (c s) + (format s "~@" + (invalid-method-initarg-method c) + (simple-condition-format-control c) + (simple-condition-format-arguments c))))) + +(defun invalid-method-initarg (method format-control &rest args) + (error 'invalid-method-initarg :method method + :format-control format-control :format-arguments args)) + +(defun check-documentation (method doc) + (unless (or (null doc) (stringp doc)) + (invalid-method-initarg method "~@<~S of ~S is neither ~S nor a ~S.~@:>" + :documentation doc 'null 'string))) +(defun check-lambda-list (method ll) + nil) -(defmethod legal-method-function-p ((object standard-method) x) - (if (functionp x) - t - "a function")) +(defun check-method-function (method fun) + (unless (functionp fun) + (invalid-method-initarg method "~@<~S of ~S is not a ~S.~@:>" + :function fun 'function))) -(defmethod legal-qualifiers-p ((object standard-method) x) +(defun check-qualifiers (method qualifiers) (flet ((improper-list () - (return-from legal-qualifiers-p "Is not a proper list."))) - (dolist-carefully (q x improper-list) - (let ((ok (legal-qualifier-p object q))) - (unless (eq ok t) - (return-from legal-qualifiers-p - (format nil "Contains ~S which ~A" q ok))))) - t)) - -(defmethod legal-qualifier-p ((object standard-method) x) - (if (and x (atom x)) - t - "is not a non-null atom")) - -(defmethod legal-slot-name-p ((object standard-method) x) - (cond ((not (symbolp x)) "is not a symbol") - (t t))) - -(defmethod legal-specializers-p ((object standard-method) x) + (invalid-method-initarg method + "~@<~S of ~S is an improper list.~@:>" + :qualifiers qualifiers))) + (dolist-carefully (q qualifiers improper-list) + (unless (and q (atom q)) + (invalid-method-initarg method + "~@<~S, in ~S ~S, is not a non-~S atom.~@:>" + q :qualifiers qualifiers 'null))))) + +(defun check-slot-name (method name) + (unless (symbolp name) + (invalid-method-initarg "~@<~S of ~S is not a ~S.~@:>" + :slot-name name 'symbol))) + +(defun check-specializers (method specializers) (flet ((improper-list () - (return-from legal-specializers-p "Is not a proper list."))) - (dolist-carefully (s x improper-list) - (let ((ok (legal-specializer-p object s))) - (unless (eq ok t) - (return-from legal-specializers-p - (format nil "Contains ~S which ~A" s ok))))) - t)) - -(defvar *allow-experimental-specializers-p* nil) - -(defmethod legal-specializer-p ((object standard-method) x) - (if (if *allow-experimental-specializers-p* - (specializerp x) - (or (classp x) - (eql-specializer-p x))) - t - "is neither a class object nor an EQL specializer")) - -(defmethod shared-initialize :before ((method standard-method) - slot-names - &key qualifiers - lambda-list - specializers - function - fast-function - documentation) + (invalid-method-initarg method + "~@<~S of ~S is an improper list.~@:>" + :specializers specializers))) + (dolist-carefully (s specializers improper-list) + (unless (specializerp s) + (invalid-method-initarg method + "~@<~S, in ~S ~S, is not a ~S.~@:>" + s :specializers specializers 'specializer))) + ;; KLUDGE: ANSI says that it's not valid to have methods + ;; specializing on classes which are "not defined", leaving + ;; unclear what the definedness of a class is; AMOP suggests that + ;; forward-referenced-classes, since they have proper names and + ;; all, are at least worthy of some level of definition. We allow + ;; methods specialized on forward-referenced-classes, but it's + ;; non-portable and potentially dubious, so + (let ((frcs (remove-if-not #'forward-referenced-class-p specializers))) + (unless (null frcs) + (style-warn "~@" + (length frcs) frcs))))) + +(defmethod shared-initialize :before + ((method standard-method) slot-names &key + qualifiers lambda-list specializers function documentation) (declare (ignore slot-names)) - (flet ((lose (initarg value string) - (error "when initializing the method ~S:~%~ - The ~S initialization argument was: ~S.~%~ - which ~A." - method initarg value string))) - (let ((check-qualifiers (legal-qualifiers-p method qualifiers)) - (check-lambda-list (legal-lambda-list-p method lambda-list)) - (check-specializers (legal-specializers-p method specializers)) - (check-fun (legal-method-function-p method - (or function - fast-function))) - (check-documentation (legal-documentation-p method documentation))) - (unless (eq check-qualifiers t) - (lose :qualifiers qualifiers check-qualifiers)) - (unless (eq check-lambda-list t) - (lose :lambda-list lambda-list check-lambda-list)) - (unless (eq check-specializers t) - (lose :specializers specializers check-specializers)) - (unless (eq check-fun t) - (lose :function function check-fun)) - (unless (eq check-documentation t) - (lose :documentation documentation check-documentation))))) - -(defmethod shared-initialize :before ((method standard-accessor-method) - slot-names - &key slot-name slot-definition) + ;; FIXME: it's not clear to me (CSR, 2006-08-09) why methods get + ;; this extra paranoia and nothing else does; either everything + ;; should be aggressively checking initargs, or nothing much should. + ;; In either case, it would probably be better to have :type + ;; declarations in slots, which would then give a suitable type + ;; error (if we implement type-checking for slots...) rather than + ;; this hand-crafted thing. + (check-qualifiers method qualifiers) + (check-lambda-list method lambda-list) + (check-specializers method specializers) + (check-method-function method function) + (check-documentation method documentation)) + +(defmethod shared-initialize :before + ((method standard-accessor-method) slot-names &key + slot-name slot-definition) (declare (ignore slot-names)) (unless slot-definition - (let ((legalp (legal-slot-name-p method slot-name))) - ;; FIXME: nasty convention; should be renamed to ILLEGAL-SLOT-NAME-P and - ;; ILLEGALP, and the convention redone to be less twisty - (unless (eq legalp t) - (error "The value of the :SLOT-NAME initarg ~A." legalp))))) + (check-slot-name method slot-name))) (defmethod shared-initialize :after ((method standard-method) slot-names - &rest initargs - &key qualifiers method-spec plist) - (declare (ignore slot-names method-spec plist)) - (initialize-method-function initargs nil method) - (setf (plist-value method 'qualifiers) qualifiers) - #+ignore - (setf (slot-value method 'closure-generator) - (method-function-closure-generator (slot-value method 'function)))) - -(defmethod shared-initialize :after ((method standard-accessor-method) - slot-names - &key) + &rest initargs &key) (declare (ignore slot-names)) - (with-slots (slot-name slot-definition) - method - (unless slot-definition - (let ((class (accessor-method-class method))) - (when (slot-class-p class) - (setq slot-definition (find slot-name (class-direct-slots class) - :key #'slot-definition-name))))) - (when (and slot-definition (null slot-name)) - (setq slot-name (slot-definition-name slot-definition))))) - -(defmethod method-qualifiers ((method standard-method)) - (plist-value method 'qualifiers)) + (initialize-method-function initargs method)) + (defvar *the-class-generic-function* (find-class 'generic-function)) @@ -229,41 +204,19 @@ (initarg-error :method-combination method-combination "a method combination object"))) - ((slot-boundp generic-function 'method-combination)) + ((slot-boundp generic-function '%method-combination)) (t (initarg-error :method-combination "not supplied" "a method combination object"))))) - -#|| -(defmethod reinitialize-instance ((generic-function standard-generic-function) - &rest initargs - &key name - lambda-list - argument-precedence-order - declarations - documentation - method-class - method-combination) - (declare (ignore documentation declarations argument-precedence-order - lambda-list name method-class method-combination)) - (macrolet ((add-initarg (check name slot-name) - `(unless ,check - (push (slot-value generic-function ,slot-name) initargs) - (push ,name initargs)))) -; (add-initarg name :name 'name) -; (add-initarg lambda-list :lambda-list 'lambda-list) -; (add-initarg argument-precedence-order -; :argument-precedence-order -; 'argument-precedence-order) -; (add-initarg declarations :declarations 'declarations) -; (add-initarg documentation :documentation 'documentation) -; (add-initarg method-class :method-class 'method-class) -; (add-initarg method-combination :method-combination 'method-combination) - (apply #'call-next-method generic-function initargs))) -||# -;;; These two are scheduled for demolition. +(defun find-generic-function (name &optional (errorp t)) + (let ((fun (and (fboundp name) (fdefinition name)))) + (cond + ((and fun (typep fun 'generic-function)) fun) + (errorp (error "No generic function named ~S." name)) + (t nil)))) + (defun real-add-named-method (generic-function-name qualifiers specializers @@ -273,11 +226,13 @@ (typep (fdefinition generic-function-name) 'generic-function)) (style-warn "implicitly creating new generic function ~S" generic-function-name)) - ;; XXX What about changing the class of the generic function if - ;; there is one? Whose job is that, anyway? Do we need something - ;; kind of like CLASS-FOR-REDEFINITION? - (let* ((generic-function - (ensure-generic-function generic-function-name)) + (let* ((existing-gf (find-generic-function generic-function-name nil)) + (generic-function + (if existing-gf + (ensure-generic-function + generic-function-name + :generic-function-class (class-of existing-gf)) + (ensure-generic-function generic-function-name))) (specs (parse-specializers specializers)) (proto (method-prototype-for-gf generic-function-name)) (new (apply #'make-instance (class-of proto) @@ -456,10 +411,10 @@ :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))))) + (when (arg-info-valid-p (gf-arg-info gf)) + (update-dfun gf)) + (map-dependents gf (lambda (dependent) + (apply #'update-dependent gf dependent args)))))) (declaim (special *lazy-dfun-compute-p*)) @@ -468,6 +423,18 @@ (loop (when (null methods) (return gf)) (real-add-method gf (pop methods) methods))) +(define-condition new-value-specialization (reference-condition error) + ((%method :initarg :method :reader new-value-specialization-method)) + (:report + (lambda (c s) + (format s "~@" + (new-value-specialization-method c) + #'(setf slot-value-using-class)))) + (:default-initargs :references + (list '(:sbcl :node "Metaobject Protocol") + '(:amop :generic-function (setf slot-value-using-class))))) + (defun real-add-method (generic-function method &optional skip-dfun-update-p) (when (method-generic-function method) (error "~@" method qualifiers))) ((short-method-combination-p mc) - (let ((mc-name (method-combination-type mc))) + (let ((mc-name (method-combination-type-name mc))) (when (or (null qualifiers) (cdr qualifiers) (and (neq (car qualifiers) :around) @@ -548,10 +526,14 @@ :generic-function generic-function :method method) (update-dfun generic-function)) + (map-dependents generic-function + (lambda (dep) + (update-dependent generic-function + dep 'add-method method))) generic-function))) (defun real-remove-method (generic-function method) - (when (eq generic-function (method-generic-function method)) + (when (eq generic-function (method-generic-function method)) (let* ((name (generic-function-name generic-function)) (specializers (method-specializers method)) (methods (generic-function-methods generic-function)) @@ -564,7 +546,11 @@ (update-ctors 'remove-method :generic-function generic-function :method method) - (update-dfun generic-function))) + (update-dfun generic-function) + (map-dependents generic-function + (lambda (dep) + (update-dependent generic-function + dep 'remove-method method))))) generic-function) (defun compute-applicable-methods-function (generic-function arguments) @@ -643,15 +629,6 @@ (defmethod specializer-class ((specializer eql-specializer)) (class-of (slot-value specializer 'object))) -(defvar *in-gf-arg-info-p* nil) -(setf (gdefinition 'arg-info-reader) - (let ((mf (initialize-method-function - (make-internal-reader-method-function - 'standard-generic-function 'arg-info) - t))) - (lambda (&rest args) (funcall mf args nil)))) - - (defun error-need-at-least-n-args (function n) (error 'simple-program-error :format-control "~@