X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fboot.lisp;h=6a8cc46530860db01941637dde7ebab75f994198;hb=961c6bf2eda5d492d5dbb7e275fe4e0931f7adf8;hp=c794df48628b4866db678554acf32cc0501d4deb;hpb=e768e8944cce654692468dae63f819ea1aa520a5;p=sbcl.git diff --git a/src/pcl/boot.lisp b/src/pcl/boot.lisp index c794df4..6a8cc46 100644 --- a/src/pcl/boot.lisp +++ b/src/pcl/boot.lisp @@ -318,40 +318,44 @@ bootstrapping. ;; belong here! (aver (not morep))))) -(defmacro defmethod (&rest args) - (multiple-value-bind (name qualifiers lambda-list body) +(defmacro defmethod (name &rest args) + (multiple-value-bind (qualifiers lambda-list body) (parse-defmethod args) `(progn - ;; KLUDGE: this double expansion is quite a monumental - ;; workaround: it comes about because of a fantastic interaction - ;; between the processing rules of CLHS 3.2.3.1 and the - ;; bizarreness of MAKE-METHOD-LAMBDA. - ;; - ;; MAKE-METHOD-LAMBDA can be called by the user, and if the - ;; lambda itself doesn't refer to outside bindings the return - ;; value must be compileable in the null lexical environment. - ;; However, the function must also refer somehow to the - ;; associated method object, so that it can call NO-NEXT-METHOD - ;; with the appropriate arguments if there is no next method -- - ;; but when the function is generated, the method object doesn't - ;; exist yet. - ;; - ;; In order to resolve this issue, we insert a literal cons cell - ;; into the body of the method lambda, return the same cons cell - ;; as part of the second (initargs) return value of - ;; MAKE-METHOD-LAMBDA, and a method on INITIALIZE-INSTANCE fills - ;; in the cell when the method is created. However, this - ;; strategy depends on having a fresh cons cell for every method - ;; lambda, which (without the workaround below) is skewered by - ;; the processing in CLHS 3.2.3.1, which permits implementations - ;; to macroexpand the bodies of EVAL-WHEN forms with both - ;; :COMPILE-TOPLEVEL and :LOAD-TOPLEVEL only once. The - ;; expansion below forces the double expansion in those cases, - ;; while expanding only once in the common case. - (eval-when (:load-toplevel) - (%defmethod-expander ,name ,qualifiers ,lambda-list ,body)) - (eval-when (:execute) - (%defmethod-expander ,name ,qualifiers ,lambda-list ,body))))) + (eval-when (:compile-toplevel :execute) + ;; :compile-toplevel is needed for subsequent forms + ;; :execute is needed for references to itself inside the body + (compile-or-load-defgeneric ',name)) + ;; KLUDGE: this double expansion is quite a monumental + ;; workaround: it comes about because of a fantastic interaction + ;; between the processing rules of CLHS 3.2.3.1 and the + ;; bizarreness of MAKE-METHOD-LAMBDA. + ;; + ;; MAKE-METHOD-LAMBDA can be called by the user, and if the + ;; lambda itself doesn't refer to outside bindings the return + ;; value must be compileable in the null lexical environment. + ;; However, the function must also refer somehow to the + ;; associated method object, so that it can call NO-NEXT-METHOD + ;; with the appropriate arguments if there is no next method -- + ;; but when the function is generated, the method object doesn't + ;; exist yet. + ;; + ;; In order to resolve this issue, we insert a literal cons cell + ;; into the body of the method lambda, return the same cons cell + ;; as part of the second (initargs) return value of + ;; MAKE-METHOD-LAMBDA, and a method on INITIALIZE-INSTANCE fills + ;; in the cell when the method is created. However, this + ;; strategy depends on having a fresh cons cell for every method + ;; lambda, which (without the workaround below) is skewered by + ;; the processing in CLHS 3.2.3.1, which permits implementations + ;; to macroexpand the bodies of EVAL-WHEN forms with both + ;; :COMPILE-TOPLEVEL and :LOAD-TOPLEVEL only once. The + ;; expansion below forces the double expansion in those cases, + ;; while expanding only once in the common case. + (eval-when (:load-toplevel) + (%defmethod-expander ,name ,qualifiers ,lambda-list ,body)) + (eval-when (:execute) + (%defmethod-expander ,name ,qualifiers ,lambda-list ,body))))) (defmacro %defmethod-expander (name qualifiers lambda-list body &environment env) @@ -588,8 +592,13 @@ bootstrapping. ;; if there is are no non-standard prior MAKE-METHOD-LAMBDA methods -- or ;; unless they're fantastically unintrusive. (let* ((method-name *method-name*) + (method-lambda-list *method-lambda-list*) + ;; Macroexpansion caused by code-walking may call make-method-lambda and + ;; end up with wrong values + (*method-name* nil) + (*method-lambda-list* nil) (generic-function-name (when method-name (car method-name))) - (specialized-lambda-list (or *method-lambda-list* + (specialized-lambda-list (or method-lambda-list (ecase (car method-lambda) (lambda (second method-lambda)) (named-lambda (third method-lambda))))) @@ -1312,9 +1321,8 @@ bootstrapping. applyp)) &body body &environment env) - (let* ((all-params (append args (when rest-arg (list rest-arg)))) - (rebindings (when (or setq-p call-next-method-p) - (mapcar (lambda (x) (list x x)) all-params)))) + (let* ((rebindings (when (or setq-p call-next-method-p) + (mapcar (lambda (x) (list x x)) parameters-setqd)))) (if (not (or call-next-method-p setq-p closurep next-method-p-p applyp)) `(locally ,@body) @@ -1337,7 +1345,6 @@ bootstrapping. (declare (optimize (sb-c:insert-step-conditions 0))) (not (null ,next-method-call)))))) (let ,rebindings - ,@(when rebindings `((declare (ignorable ,@all-params)))) ,@body))))) ;;; CMUCL comment (Gerd Moellmann): @@ -2201,12 +2208,14 @@ bootstrapping. (finalize-inheritance ,gf-class))) (remf ,all-keys :generic-function-class) (remf ,all-keys :environment) - (let ((combin (getf ,all-keys :method-combination '.shes-not-there.))) - (unless (eq combin '.shes-not-there.) - (setf (getf ,all-keys :method-combination) - (find-method-combination (class-prototype ,gf-class) - (car combin) - (cdr combin))))) + (let ((combin (getf ,all-keys :method-combination))) + (etypecase combin + (cons + (setf (getf ,all-keys :method-combination) + (find-method-combination (class-prototype ,gf-class) + (car combin) + (cdr combin)))) + ((or null method-combination)))) (let ((method-class (getf ,all-keys :method-class '.shes-not-there.))) (unless (eq method-class '.shes-not-there.) (setf (getf ,all-keys :method-class) @@ -2612,14 +2621,13 @@ bootstrapping. ;;; is really implemented. (defun parse-defmethod (cdr-of-form) (declare (list cdr-of-form)) - (let ((name (pop cdr-of-form)) - (qualifiers ()) + (let ((qualifiers ()) (spec-ll ())) (loop (if (and (car cdr-of-form) (atom (car cdr-of-form))) (push (pop cdr-of-form) qualifiers) (return (setq qualifiers (nreverse qualifiers))))) (setq spec-ll (pop cdr-of-form)) - (values name qualifiers spec-ll cdr-of-form))) + (values qualifiers spec-ll cdr-of-form))) (defun parse-specializers (generic-function specializers) (declare (list specializers))