0.7.9.1:
[sbcl.git] / src / pcl / std-class.lisp
index 0d0d1e2..7b4c293 100644 (file)
                  *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))
 
   (let ((method (get-method generic-function () (list class) nil)))
     (when method (remove-method generic-function method))))
 \f
-;;; 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
 ;;;
 ;;; *** 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)