0.8.16.43: Fixes for various CLOS/MOP bugs
[sbcl.git] / src / pcl / std-class.lisp
index cec50b1..d60c04c 100644 (file)
 ;;;; various class accessors that are a little more complicated than can be
 ;;;; done with automatically generated reader methods
 
-(defmethod class-prototype ((class std-class))
-  (with-slots (prototype) class
-    (or prototype (setq prototype (allocate-instance class)))))
-
-(defmethod class-prototype ((class structure-class))
-  (with-slots (prototype wrapper defstruct-constructor) class
-    (or prototype
-       (setq prototype
-             (if defstruct-constructor
-                 (allocate-instance class)
-                 (allocate-standard-instance wrapper))))))
-
-(defmethod class-prototype ((class condition-class))
-  (with-slots (prototype) class
-    (or prototype (setf prototype (allocate-instance class)))))
+(defmethod class-prototype :before (class)
+  (unless (class-finalized-p class)
+    (error "~S not yet finalized, cannot allocate a prototype." class)))
+
+;;; KLUDGE: For some reason factoring the common body into a function
+;;; breaks PCL bootstrapping, so just generate it with a macrolet for
+;;; all.
+(macrolet ((def (class)
+             `(defmethod class-prototype ((class ,class))
+                (with-slots (prototype) class
+                  (or prototype 
+                      (setf prototype (allocate-instance class)))))))
+  (def std-class)
+  (def condition-class)
+  (def structure-class))
 
 (defmethod class-direct-default-initargs ((class slot-class))
   (plist-value class 'direct-default-initargs))
   (setf (info :type :translator specl)
         (constantly (make-member-type :members (list (specializer-object specl))))))
 
-\f
 (defun real-load-defclass (name metaclass-name supers slots other
                            readers writers slot-names)
   (with-single-package-locked-error (:symbol name "defining ~S as a class")
             (make-instance 'forward-referenced-class
                            :name s)))))
 
-(defun ensure-class-values (class args)
-  (let* ((initargs (copy-list args))
-        (unsupplied (list 1))
-        (supplied-meta   (getf initargs :metaclass unsupplied))
-        (supplied-supers (getf initargs :direct-superclasses unsupplied))
-        (supplied-slots  (getf initargs :direct-slots unsupplied))
-        (meta
-          (cond ((neq supplied-meta unsupplied)
-                 (find-class supplied-meta))
-                ((or (null class)
-                     (forward-referenced-class-p 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
-    (do ((direct-slots (getf initargs :direct-slots) (cdr direct-slots)))
-       ((endp direct-slots) nil)
-      (destructuring-bind (slot &rest more) direct-slots
-       (let ((slot-name (getf slot :name)))
-         (when (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 codebase that are required to be
-           ;; of type PROGRAM-ERROR.
-           (error 'simple-program-error
-                  :format-control "~@<There is more than one direct slot ~
-                                   with name ~S.~:>"
-                  :format-arguments (list slot-name)))
-         (do ((stuff slot (cddr stuff)))
-             ((endp stuff) nil)
-           (destructuring-bind (option value &rest more) stuff
-             (cond
-               ((and (member option '(:allocation :type
-                                      :initform :documentation))
-                     (not (eq unsupplied
-                              (getf more option unsupplied))))
-                (error 'simple-program-error
-                       :format-control "~@<Duplicate slot option ~S for ~
-                                        slot named ~S.~:>"
-                       :format-arguments (list option slot-name)))
-               ((and (eq option :readers)
-                     (notevery #'symbolp value))
-                (error 'simple-program-error
-                       :format-control "~@<Slot reader names for slot ~
-                                        named ~S must be symbols.~:>"
-                       :format-arguments (list slot-name)))
-               ((and (eq option :initargs)
-                     (notevery #'symbolp value))
-                (error 'simple-program-error
-                       :format-control "~@<Slot initarg names for slot ~
-                                        named ~S must be symbols.~:>"
-                       :format-arguments (list 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.~:>"
-                   :format-arguments (list name class)))
-    (let ((metaclass 0)
-         (default-initargs 0))
-      (do ((args initargs (cddr args)))
-         ((endp args) nil)
-       (case (car args)
-         (:metaclass
-          (when (> (incf metaclass) 1)
-            (error 'simple-program-error
-                   :format-control "~@<More than one :METACLASS ~
-                                    option specified.~:>")))
-         (:direct-default-initargs
-          (when (> (incf default-initargs) 1)
-            (error 'simple-program-error
-                   :format-control "~@<More than one :DEFAULT-INITARGS ~
-                                    option specified.~:>"))))))
-    (remf initargs :metaclass)
-    (loop (unless (remf initargs :direct-superclasses) (return)))
-    (loop (unless (remf initargs :direct-slots) (return)))
-    (values
-     meta
-     (nconc
-      (when (neq supplied-supers unsupplied)
-       (list :direct-superclasses (mapcar #'fix-super supplied-supers)))
-      (when (neq supplied-slots unsupplied)
-       (list :direct-slots supplied-slots))
-      initargs))))
+(defun ensure-class-values (class initargs)
+  (let (metaclass metaclassp reversed-plist)
+    (doplist (key val) initargs
+        (cond ((eq key :metaclass)
+               (setf metaclass val
+                     metaclassp key))
+              (t
+               (when (eq key :direct-superclasses)
+                 (setf val (mapcar #'fix-super val)))
+               (setf reversed-plist (list* val key reversed-plist)))))
+    (values (cond (metaclassp
+                   (find-class metaclass))
+                  ((or (null class) (forward-referenced-class-p class))
+                   *the-class-standard-class*)
+                  (t
+                   (class-of class)))
+            (nreverse reversed-plist))))
+
 \f
 (defmethod shared-initialize :after
           ((class std-class)