X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fstd-class.lisp;h=7b4c2933d8c234df790bb44fd84434e2ccf3b32e;hb=6c4d4d984b1af6b2a73568cec3ab9c8795cff2da;hp=8dd9ea1c06bd2d3c54c58991d6f7e5aeda221a65;hpb=63cef087068afc157283c0a05ae1f16b962303aa;p=sbcl.git diff --git a/src/pcl/std-class.lisp b/src/pcl/std-class.lisp index 8dd9ea1..7b4c293 100644 --- a/src/pcl/std-class.lisp +++ b/src/pcl/std-class.lisp @@ -375,6 +375,40 @@ *the-class-standard-class*) (t (class-of class))))) + ;; KLUDGE: It seemed to me initially that there ought to be a way + ;; of collecting all the erroneous problems in one go, rather than + ;; this way of solving the problem of signalling the errors that + ;; we are required to, which stops at the first bogus input. + ;; However, after playing around a little, I couldn't find that + ;; way, so I've left it as is, but if someone does come up with a + ;; better way... -- CSR, 2002-09-08 + (loop for (slot . more) on (getf initargs :direct-slots) + for slot-name = (getf slot :name) + if (some (lambda (s) (eq slot-name (getf s :name))) more) + ;; FIXME: It's quite possible that we ought to define an + ;; SB-INT:PROGRAM-ERROR function to signal these and other + ;; errors throughout the code base that are required to be + ;; of type PROGRAM-ERROR. + do (error 'simple-program-error + :format-control "More than one direct slot with name ~S." + :format-arguments (list slot-name)) + else + do (loop for (option value . more) on slot by #'cddr + when (and (member option + '(:allocation :type + :initform :documentation)) + (not (eq unsupplied + (getf more option unsupplied)))) + do (error 'simple-program-error + :format-control "Duplicate slot option ~S for slot ~S." + :format-arguments (list option slot-name)))) + (loop for (initarg . more) on (getf initargs :direct-default-initargs) + for name = (car initarg) + when (some (lambda (a) (eq (car a) name)) more) + do (error 'simple-program-error + :format-control "Duplicate initialization argument ~ + name ~S in :default-initargs of class ~A." + :format-arguments (list name class))) (loop (unless (remf initargs :metaclass) (return))) (loop (unless (remf initargs :direct-superclasses) (return))) (loop (unless (remf initargs :direct-slots) (return))) @@ -426,7 +460,7 @@ (setf (plist-value class 'class-slot-cells) (let (collect) (dolist (dslotd direct-slots) - (when (eq (slot-definition-allocation dslotd) class) + (when (eq :class (slot-definition-allocation dslotd)) (let ((initfunction (slot-definition-initfunction dslotd))) (push (cons (slot-definition-name dslotd) (if initfunction @@ -465,13 +499,6 @@ (lambda (dependent) (apply #'update-dependent class dependent initargs)))) -(defmethod shared-initialize :after ((slotd standard-slot-definition) - slot-names &key) - (declare (ignore slot-names)) - (with-slots (allocation class) - slotd - (setq allocation (if (eq allocation :class) class allocation)))) - (defmethod shared-initialize :after ((slotd structure-slot-definition) slot-names &key (allocation :instance)) @@ -481,11 +508,10 @@ (defun make-structure-class-defstruct-form (name direct-slots include) (let* ((conc-name (intern (format nil "~S structure class " name))) - (constructor (intern (format nil "~A constructor" conc-name))) + (constructor (intern (format nil "~Aconstructor" conc-name))) (defstruct `(defstruct (,name ,@(when include `((:include ,(class-name include)))) - (:print-function print-std-instance) (:predicate nil) (:conc-name ,conc-name) (:constructor ,constructor ()) @@ -650,9 +676,24 @@ ;;; This is called by :after shared-initialize whenever a class is initialized ;;; or reinitialized. The class may or may not be finalized. (defun update-class (class finalizep) + ;; Comment from Gerd Moellmann: + ;; + ;; Note that we can't simply delay the finalization when CLASS has + ;; no forward referenced superclasses because that causes bootstrap + ;; problems. + (when (and (not finalizep) + (not (class-finalized-p class)) + (not (class-has-a-forward-referenced-superclass-p class))) + (finalize-inheritance class) + (return-from update-class)) (when (or finalizep (class-finalized-p class) (not (class-has-a-forward-referenced-superclass-p class))) (update-cpl class (compute-class-precedence-list class)) + ;; This invocation of UPDATE-SLOTS, in practice, finalizes the + ;; class. The hoops above are to ensure that FINALIZE-INHERITANCE + ;; is called at finalization, so that MOP programmers can hook + ;; into the system as described in "Class Finalization Protocol" + ;; (section 5.5.2 of AMOP). (update-slots class (compute-slots class)) (update-gfs-of-class class) (update-inits class (compute-default-initargs class)) @@ -686,8 +727,9 @@ (class-slots ())) (dolist (eslotd eslotds) (let ((alloc (slot-definition-allocation eslotd))) - (cond ((eq alloc :instance) (push eslotd instance-slots)) - ((classp alloc) (push eslotd class-slots))))) + (case alloc + (:instance (push eslotd instance-slots)) + (:class (push eslotd class-slots))))) ;; If there is a change in the shape of the instances then the ;; old class is now obsolete. @@ -732,7 +774,7 @@ (let (collect) (dolist (eslotd eslotds) (push (assoc (slot-definition-name eslotd) - (class-slot-cells (slot-definition-allocation eslotd))) + (class-slot-cells (slot-definition-class eslotd))) collect)) (nreverse collect))) @@ -829,8 +871,9 @@ (class-slots ())) (dolist (eslotd eslotds) (let ((alloc (slot-definition-allocation eslotd))) - (cond ((eq alloc :instance) (push eslotd instance-slots)) - ((classp alloc) (push eslotd class-slots))))) + (case alloc + (:instance (push eslotd instance-slots)) + (:class (push eslotd class-slots))))) (let ((nlayout (compute-layout cpl instance-slots))) (dolist (eslotd instance-slots) (setf (slot-definition-location eslotd) @@ -838,7 +881,7 @@ (dolist (eslotd class-slots) (setf (slot-definition-location eslotd) (assoc (slot-definition-name eslotd) - (class-slot-cells (slot-definition-allocation eslotd))))) + (class-slot-cells (slot-definition-class eslotd))))) (mapc #'initialize-internal-slot-functions eslotds) eslotds)) @@ -971,9 +1014,9 @@ (let ((method (get-method generic-function () (list class) nil))) (when method (remove-method generic-function method)))) -;;; make-reader-method-function and make-write-method function are NOT part of -;;; the standard protocol. They are however useful, PCL makes uses makes use -;;; of them internally and documents them for PCL users. +;;; MAKE-READER-METHOD-FUNCTION and MAKE-WRITE-METHOD function are NOT +;;; part of the standard protocol. They are however useful, PCL makes +;;; use of them internally and documents them for PCL users. ;;; ;;; *** This needs work to make type testing by the writer functions which ;;; *** do type testing faster. The idea would be to have one constructor @@ -981,7 +1024,7 @@ ;;; ;;; *** There is a subtle bug here which is going to have to be fixed. ;;; *** Namely, the simplistic use of the template has to be fixed. We -;;; *** have to give the optimize-slot-value method the user might have +;;; *** have to give the OPTIMIZE-SLOT-VALUE method the user might have ;;; *** defined for this metaclass a chance to run. (defmethod make-reader-method-function ((class slot-class) slot-name) @@ -1006,14 +1049,13 @@ (eq (class-of class) new-super-meta-class)))) (defun force-cache-flushes (class) - (let* ((owrapper (class-wrapper class)) - (state (wrapper-state owrapper))) + (let* ((owrapper (class-wrapper class))) ;; We only need to do something if the state is still T. If the ;; state isn't T, it will be FLUSH or OBSOLETE, and both of those ;; will already be doing what we want. In particular, we must be ;; sure we never change an OBSOLETE into a FLUSH since OBSOLETE ;; means do what FLUSH does and then some. - (when (eq state t) ; FIXME: should be done through INVALID-WRAPPER-P + (unless (invalid-wrapper-p owrapper) (let ((nwrapper (make-wrapper (wrapper-no-of-instance-slots owrapper) class))) (setf (wrapper-instance-slots-layout nwrapper) @@ -1029,9 +1071,9 @@ (declare (ignore owrapper)) (set-wrapper instance nwrapper)) -;;; make-instances-obsolete can be called by user code. It will cause the -;;; next access to the instance (as defined in 88-002R) to trap through the -;;; update-instance-for-redefined-class mechanism. +;;; MAKE-INSTANCES-OBSOLETE can be called by user code. It will cause +;;; the next access to the instance (as defined in 88-002R) to trap +;;; through the UPDATE-INSTANCE-FOR-REDEFINED-CLASS mechanism. (defmethod make-instances-obsolete ((class std-class)) (let* ((owrapper (class-wrapper class)) (nwrapper (make-wrapper (wrapper-no-of-instance-slots owrapper) @@ -1049,8 +1091,8 @@ (defmethod make-instances-obsolete ((class symbol)) (make-instances-obsolete (find-class class))) -;;; obsolete-instance-trap is the internal trap that is called when we see -;;; an obsolete instance. The times when it is called are: +;;; OBSOLETE-INSTANCE-TRAP is the internal trap that is called when we +;;; see an obsolete instance. The times when it is called are: ;;; - when the instance is involved in method lookup ;;; - when attempting to access a slot of an instance ;;; @@ -1068,12 +1110,13 @@ ;;; sure that the traps are only happening when they should, and that ;;; the trap methods are computing appropriate new wrappers. -;;; obsolete-instance-trap might be called on structure instances -;;; after a structure is redefined. In most cases, obsolete-instance-trap -;;; will not be able to fix the old instance, so it must signal an -;;; error. The hard part of this is that the error system and debugger -;;; might cause obsolete-instance-trap to be called again, so in that -;;; case, we have to return some reasonable wrapper, instead. +;;; OBSOLETE-INSTANCE-TRAP might be called on structure instances +;;; after a structure is redefined. In most cases, +;;; OBSOLETE-INSTANCE-TRAP will not be able to fix the old instance, +;;; so it must signal an error. The hard part of this is that the +;;; error system and debugger might cause OBSOLETE-INSTANCE-TRAP to be +;;; called again, so in that case, we have to return some reasonable +;;; wrapper, instead. (defvar *in-obsolete-instance-trap* nil) (defvar *the-wrapper-of-structure-object* @@ -1151,18 +1194,7 @@ plist) nwrapper))) -(defmacro copy-instance-internal (instance) - `(progn - (let* ((class (class-of instance)) - (copy (allocate-instance class))) - (if (std-instance-p ,instance) - (setf (std-instance-slots ,instance) - (std-instance-slots ,instance)) - (setf (fsc-instance-slots ,instance) - (fsc-instance-slots ,instance))) - copy))) - -(defun change-class-internal (instance new-class) +(defun change-class-internal (instance new-class initargs) (let* ((old-class (class-of instance)) (copy (allocate-instance new-class)) (new-wrapper (get-wrapper copy)) @@ -1181,7 +1213,8 @@ (let ((old-position (posq new-slot old-layout))) (when old-position (setf (clos-slots-ref new-slots new-position) - (clos-slots-ref old-slots old-position)))))) + (clos-slots-ref old-slots old-position)))) + (incf new-position))) ;; "The values of slots specified as shared in the class CFROM and ;; as local in the class CTO are retained." @@ -1194,31 +1227,37 @@ ;; old instance point to the new storage. (swap-wrappers-and-slots instance copy) - (update-instance-for-different-class copy instance) + (apply #'update-instance-for-different-class copy instance initargs) instance)) (defmethod change-class ((instance standard-object) - (new-class standard-class)) - (change-class-internal instance new-class)) + (new-class standard-class) + &rest initargs) + (change-class-internal instance new-class initargs)) (defmethod change-class ((instance funcallable-standard-object) - (new-class funcallable-standard-class)) - (change-class-internal instance new-class)) + (new-class funcallable-standard-class) + &rest initargs) + (change-class-internal instance new-class initargs)) (defmethod change-class ((instance standard-object) - (new-class funcallable-standard-class)) + (new-class funcallable-standard-class) + &rest initargs) + (declare (ignore initargs)) (error "You can't change the class of ~S to ~S~@ because it isn't already an instance with metaclass ~S." instance new-class 'standard-class)) (defmethod change-class ((instance funcallable-standard-object) - (new-class standard-class)) + (new-class standard-class) + &rest initargs) + (declare (ignore initargs)) (error "You can't change the class of ~S to ~S~@ because it isn't already an instance with metaclass ~S." instance new-class 'funcallable-standard-class)) -(defmethod change-class ((instance t) (new-class-name symbol)) - (change-class instance (find-class new-class-name))) +(defmethod change-class ((instance t) (new-class-name symbol) &rest initargs) + (apply #'change-class instance (find-class new-class-name) initargs)) ;;;; The metaclass BUILT-IN-CLASS ;;;;