:direct-superclasses supers
:direct-slots slots
:definition-source `((defclass ,name)
- ,*load-truename*)
+ ,*load-pathname*)
other)))
;; Defclass of a class with a forward-referenced superclass does not
;; have a wrapper. RES is the incomplete PCL class. The Lisp class
*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)))
(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
(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))
;;; 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))
(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.
(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)))
(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)
(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))
(or (eq new-super-meta-class *the-class-std-class*)
(eq (class-of class) new-super-meta-class))))
\f
+;;; What this does depends on which of the four possible values of
+;;; LAYOUT-INVALID the PCL wrapper has; the simplest case is when it
+;;; is (:FLUSH <wrapper>) or (:OBSOLETE <wrapper>), when there is
+;;; nothing to do, as the new wrapper has already been created. If
+;;; LAYOUT-INVALID returns NIL, then we invalidate it (setting it to
+;;; (:FLUSH <wrapper>); UPDATE-SLOTS later gets to choose whether or
+;;; not to "upgrade" this to (:OBSOLETE <wrapper>).
+;;;
+;;; This leaves the case where LAYOUT-INVALID returns T, which happens
+;;; when REGISTER-LAYOUT has invalidated a superclass of CLASS (which
+;;; invalidated all the subclasses in SB-KERNEL land). Again, here we
+;;; must flush the caches and allow UPDATE-SLOTS to decide whether to
+;;; obsolete the wrapper.
+;;;
+;;; FIXME: either here or in INVALID-WRAPPER-P looks like a good place
+;;; for (AVER (NOT (EQ (SB-KERNEL:LAYOUT-INVALID OWRAPPER)
+;;; :UNINITIALIZED)))
+;;;
+;;; Thanks to Gerd Moellmann for the explanation. -- CSR, 2002-10-29
(defun force-cache-flushes (class)
(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.
- (unless (invalid-wrapper-p owrapper)
+ ;; We only need to do something if the wrapper is still valid. If
+ ;; the wrapper isn't valid, state 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 (or (not (invalid-wrapper-p owrapper))
+ ;; KLUDGE: despite the observations above, this remains
+ ;; a violation of locality or what might be considered
+ ;; good style. There has to be a better way! -- CSR,
+ ;; 2002-10-29
+ (eq (sb-kernel:layout-invalid owrapper) t))
(let ((nwrapper (make-wrapper (wrapper-no-of-instance-slots owrapper)
class)))
(setf (wrapper-instance-slots-layout nwrapper)
(or (eq s *the-class-t*)
(eq s *the-class-stream*)))
\f
+;;; Some necessary methods for FORWARD-REFERENCED-CLASS
+(defmethod class-direct-slots ((class forward-referenced-class)) ())
+(defmethod class-direct-default-initargs ((class forward-referenced-class)) ())
+(macrolet ((def (method)
+ `(defmethod ,method ((class forward-referenced-class))
+ (error "~@<~I~S was called on a forward referenced class:~2I~_~S~:>"
+ ',method class))))
+ (def class-default-initargs)
+ (def class-precedence-list)
+ (def class-slots))
+
(defmethod validate-superclass ((c slot-class)
(f forward-referenced-class))
t)