0.7.9.29:
[sbcl.git] / src / pcl / std-class.lisp
index bf55281..5e5f933 100644 (file)
 (defmethod class-default-initargs ((class slot-class))
   (plist-value class 'default-initargs))
 
-(defmethod class-constructors ((class slot-class))
-  (plist-value class 'constructors))
-
 (defmethod class-slot-cells ((class std-class))
   (plist-value class 'class-slot-cells))
 \f
   (with-slots (direct-methods) specializer
     (or (cdr direct-methods)
        (setf (cdr direct-methods)
-             (gathering1 (collecting-once)
+             (let (collect)
                (dolist (m (car direct-methods))
-                 (gather1 (method-generic-function m))))))))
+                  ;; the old PCL code used COLLECTING-ONCE which used
+                  ;; #'EQ to check for newness
+                 (pushnew (method-generic-function m) collect :test #'eq))
+                (nreverse collect))))))
 \f
 ;;; This hash table is used to store the direct methods and direct generic
 ;;; functions of EQL specializers. Each value in the table is the cons.
     (when entry
       (or (cdr entry)
          (setf (cdr entry)
-               (gathering1 (collecting-once)
+               (let (collect)
                  (dolist (m (car entry))
-                   (gather1 (method-generic-function m)))))))))
+                   (pushnew (method-generic-function m) collect :test #'eq))
+                  (nreverse collect)))))))
 
 (defun map-specializers (function)
-  (map-all-classes #'(lambda (class)
-                      (funcall function (class-eq-specializer class))
-                      (funcall function class)))
-  (maphash #'(lambda (object methods)
-              (declare (ignore methods))
-              (intern-eql-specializer object))
+  (map-all-classes (lambda (class)
+                    (funcall function (class-eq-specializer class))
+                    (funcall function class)))
+  (maphash (lambda (object methods)
+            (declare (ignore methods))
+            (intern-eql-specializer object))
           *eql-specializer-methods*)
-  (maphash #'(lambda (object specl)
-              (declare (ignore object))
-              (funcall function specl))
+  (maphash (lambda (object specl)
+            (declare (ignore object))
+            (funcall function specl))
           *eql-specializer-table*)
   nil)
 
 (defun map-all-generic-functions (function)
   (let ((all-generic-functions (make-hash-table :test 'eq)))
-    (map-specializers #'(lambda (specl)
-                         (dolist (gf (specializer-direct-generic-functions
-                                      specl))
-                           (unless (gethash gf all-generic-functions)
-                             (setf (gethash gf all-generic-functions) t)
-                             (funcall function gf))))))
+    (map-specializers (lambda (specl)
+                       (dolist (gf (specializer-direct-generic-functions
+                                    specl))
+                         (unless (gethash gf all-generic-functions)
+                           (setf (gethash gf all-generic-functions) t)
+                           (funcall function gf))))))
   nil)
 
 (defmethod shared-initialize :after ((specl class-eq-specializer)
                    :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
 (defmethod ensure-class-using-class (name (class null) &rest args &key)
   (multiple-value-bind (meta initargs)
       (ensure-class-values class args)
-    (inform-type-system-about-class (class-prototype meta) name);***
     (setf class (apply #'make-instance meta :name name initargs)
          (find-class name) class)
-    (inform-type-system-about-class class name)                        ;***
     class))
 
 (defmethod ensure-class-using-class (name (class pcl-class) &rest args &key)
     (unless (eq (class-of class) meta) (change-class class meta))
     (apply #'reinitialize-instance class initargs)
     (setf (find-class name) class)
-    (inform-type-system-about-class class name)                        ;***
     class))
 
 (defmethod class-predicate-name ((class t))
   'constantly-nil)
 
+(defun fix-super (s)
+  (cond ((classp s) s)
+        ((not (legal-class-name-p s))
+          (error "~S is not a class or a legal class name." s))
+        (t
+          (or (find-class s nil)
+              (setf (find-class s)
+                      (make-instance 'forward-referenced-class
+                                     :name s))))))
+
 (defun ensure-class-values (class args)
   (let* ((initargs (copy-list args))
         (unsupplied (list 1))
                  *the-class-standard-class*)
                 (t
                  (class-of class)))))
-    (flet ((fix-super (s)
-            (cond ((classp s) s)
-                  ((not (legal-class-name-p s))
-                   (error "~S is not a class or a legal class name." s))
-                  (t
-                   (or (find-class s nil)
-                       (setf (find-class s)
-                             (make-instance 'forward-referenced-class
-                                            :name s)))))))
-      (loop (unless (remf initargs :metaclass) (return)))
-      (loop (unless (remf initargs :direct-superclasses) (return)))
-      (loop (unless (remf initargs :direct-slots) (return)))
-      (values meta
-             (list* :direct-superclasses
-                    (and (neq supplied-supers unsupplied)
-                         (mapcar #'fix-super supplied-supers))
-                    :direct-slots
-                    (and (neq supplied-slots unsupplied) supplied-slots)
-                    initargs)))))
+    ;; 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)))
+    (values meta
+            (list* :direct-superclasses
+                   (and (neq supplied-supers unsupplied)
+                        (mapcar #'fix-super supplied-supers))
+                   :direct-slots
+                   (and (neq supplied-slots unsupplied) supplied-slots)
+                   initargs))))
 \f
-#|| ; since it doesn't do anything
-(defmethod shared-initialize :before ((class std-class)
-                                     slot-names
-                                     &key direct-superclasses)
-  (declare (ignore slot-names))
-  ;; *** error checking
-  )
-||#
 
 (defmethod shared-initialize :after
           ((class std-class)
       (setq direct-default-initargs
            (plist-value class 'direct-default-initargs)))
   (setf (plist-value class 'class-slot-cells)
-       (gathering1 (collecting)
+       (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)))
-               (gather1 (cons (slot-definition-name dslotd)
+               (push (cons (slot-definition-name dslotd)
                               (if initfunction
                                   (funcall initfunction)
-                                  +slot-unbound+))))))))
+                                  +slot-unbound+))
+                      collect))))
+          (nreverse collect)))
   (setq predicate-name (if predicate-name-p
                           (setf (slot-value class 'predicate-name)
                                 (car predicate-name))
                                         &rest initargs
                                         &key)
   (map-dependents class
-                 #'(lambda (dependent)
-                     (apply #'update-dependent class dependent initargs))))
+                 (lambda (dependent)
+                   (apply #'update-dependent class dependent initargs))))
+
+(defmethod shared-initialize :after ((slotd structure-slot-definition)
+                                    slot-names
+                                    &key (allocation :instance))
+  (declare (ignore slot-names))
+  (unless (eq allocation :instance)
+    (error "Structure slots must have :INSTANCE allocation.")))
+
+(defun make-structure-class-defstruct-form (name direct-slots include)
+  (let* ((conc-name (intern (format nil "~S structure class " name)))
+         (constructor (intern (format nil "~Aconstructor" conc-name)))
+         (defstruct `(defstruct (,name
+                                 ,@(when include
+                                         `((:include ,(class-name include))))
+                                 (:predicate nil)
+                                 (:conc-name ,conc-name)
+                                 (:constructor ,constructor ())
+                                 (:copier nil))
+                      ,@(mapcar (lambda (slot)
+                                  `(,(slot-definition-name slot)
+                                    +slot-unbound+))
+                                direct-slots)))
+         (reader-names (mapcar (lambda (slotd)
+                                 (intern (format nil
+                                                 "~A~A reader"
+                                                 conc-name
+                                                 (slot-definition-name
+                                                  slotd))))
+                               direct-slots))
+         (writer-names (mapcar (lambda (slotd)
+                                 (intern (format nil
+                                                 "~A~A writer"
+                                                 conc-name
+                                                 (slot-definition-name
+                                                  slotd))))
+                               direct-slots))
+         (readers-init
+           (mapcar (lambda (slotd reader-name)
+                     (let ((accessor
+                             (slot-definition-defstruct-accessor-symbol
+                              slotd)))
+                       `(defun ,reader-name (obj)
+                         (declare (type ,name obj))
+                         (,accessor obj))))
+                   direct-slots reader-names))
+         (writers-init
+           (mapcar (lambda (slotd writer-name)
+                     (let ((accessor
+                             (slot-definition-defstruct-accessor-symbol
+                              slotd)))
+                       `(defun ,writer-name (nv obj)
+                         (declare (type ,name obj))
+                         (setf (,accessor obj) nv))))
+                   direct-slots writer-names))
+         (defstruct-form
+             `(progn
+               ,defstruct
+               ,@readers-init ,@writers-init
+               (cons nil nil))))
+    (values defstruct-form constructor reader-names writer-names)))
 
 (defmethod shared-initialize :after
       ((class structure-class)
     (if direct-slots-p
        (setf (slot-value class 'direct-slots)
              (setq direct-slots
-                   (mapcar #'(lambda (pl)
-                               (when defstruct-p
-                                 (let* ((slot-name (getf pl :name))
-                                        (acc-name
-                                         (format nil
-                                                 "~S structure class ~A"
-                                                 name slot-name))
-                                        (accessor (intern acc-name)))
-                                   (setq pl (list* :defstruct-accessor-symbol
-                                                   accessor pl))))
-                               (make-direct-slotd class pl))
+                   (mapcar (lambda (pl)
+                             (when defstruct-p
+                               (let* ((slot-name (getf pl :name))
+                                      (acc-name
+                                       (format nil
+                                               "~S structure class ~A"
+                                               name slot-name))
+                                      (accessor (intern acc-name)))
+                                 (setq pl (list* :defstruct-accessor-symbol
+                                                 accessor pl))))
+                             (make-direct-slotd class pl))
                            direct-slots)))
        (setq direct-slots (slot-value class 'direct-slots)))
     (when defstruct-p
-      (let* ((include (car (slot-value class 'direct-superclasses)))
-            (conc-name (intern (format nil "~S structure class " name)))
-            (constructor (intern (format nil "~A constructor" conc-name)))
-            (defstruct `(defstruct (,name
-                                     ,@(when include
-                                         `((:include ,(class-name include))))
-                                     (:print-function print-std-instance)
-                                     (:predicate nil)
-                                     (:conc-name ,conc-name)
-                                     (:constructor ,constructor ())
-                                     (:copier nil))
-                          ,@(mapcar (lambda (slot)
-                                      `(,(slot-definition-name slot)
-                                        +slot-unbound+))
-                                    direct-slots)))
-            (reader-names (mapcar (lambda (slotd)
-                                    (intern (format nil
-                                                    "~A~A reader"
-                                                    conc-name
-                                                    (slot-definition-name
-                                                     slotd))))
-                                  direct-slots))
-            (writer-names (mapcar (lambda (slotd)
-                                    (intern (format nil
-                                                    "~A~A writer"
-                                                    conc-name
-                                                    (slot-definition-name
-                                                     slotd))))
-                                  direct-slots))
-            (readers-init
-             (mapcar (lambda (slotd reader-name)
-                       (let ((accessor
-                              (slot-definition-defstruct-accessor-symbol
-                               slotd)))
-                         `(defun ,reader-name (obj)
-                            (declare (type ,name obj))
-                            (,accessor obj))))
-                     direct-slots reader-names))
-            (writers-init
-             (mapcar (lambda (slotd writer-name)
-                       (let ((accessor
-                              (slot-definition-defstruct-accessor-symbol
-                               slotd)))
-                         `(defun ,writer-name (nv obj)
-                            (declare (type ,name obj))
-                            (setf (,accessor obj) nv))))
-                     direct-slots writer-names))
-            (defstruct-form
-              `(progn
-                 ,defstruct
-                 ,@readers-init ,@writers-init
-                 (cons nil nil))))
-       (unless (structure-type-p name) (eval defstruct-form))
-       (mapc #'(lambda (dslotd reader-name writer-name)
+      (let ((include (car (slot-value class 'direct-superclasses))))
+        (multiple-value-bind (defstruct-form constructor reader-names writer-names)
+            (make-structure-class-defstruct-form name direct-slots include)
+          (unless (structure-type-p name) (eval defstruct-form))
+          (mapc (lambda (dslotd reader-name writer-name)
                  (let* ((reader (gdefinition reader-name))
                         (writer (when (gboundp writer-name)
                                   (gdefinition writer-name))))
                          reader)
                    (setf (slot-value dslotd 'internal-writer-function)
                          writer)))
-             direct-slots reader-names writer-names)
-       (setf (slot-value class 'defstruct-form) defstruct-form)
-       (setf (slot-value class 'defstruct-constructor) constructor))))
-  (add-direct-subclasses class direct-superclasses)
-  (setf (slot-value class 'class-precedence-list)
-       (compute-class-precedence-list class))
-  (setf (slot-value class 'slots) (compute-slots class))
-  (let ((lclass (cl:find-class (class-name class))))
-    (setf (sb-kernel:class-pcl-class lclass) class)
-    (setf (slot-value class 'wrapper) (sb-kernel:class-layout lclass)))
-  (update-pv-table-cache-info class)
-  (setq predicate-name (if predicate-name-p
+                direct-slots reader-names writer-names)
+          (setf (slot-value class 'defstruct-form) defstruct-form)
+          (setf (slot-value class 'defstruct-constructor) constructor))))
+    (add-direct-subclasses class direct-superclasses)
+    (setf (slot-value class 'class-precedence-list)
+            (compute-class-precedence-list class))
+    (setf (slot-value class 'slots) (compute-slots class))
+    (let ((lclass (cl:find-class (class-name class))))
+      (setf (sb-kernel:class-pcl-class lclass) class)
+      (setf (slot-value class 'wrapper) (sb-kernel:class-layout lclass)))
+    (update-pv-table-cache-info class)
+    (setq predicate-name (if predicate-name-p
                           (setf (slot-value class 'predicate-name)
-                                (car predicate-name))
+                                   (car predicate-name))
                           (or (slot-value class 'predicate-name)
                               (setf (slot-value class 'predicate-name)
-                                    (make-class-predicate-name
-                                     (class-name class))))))
-  (make-class-predicate class predicate-name)
-  (add-slot-accessors class direct-slots))
-
+                                       (make-class-predicate-name
+                                        (class-name class))))))
+    (make-class-predicate class predicate-name)
+    (add-slot-accessors class direct-slots)))
+  
 (defmethod direct-slot-definition-class ((class structure-class) initargs)
   (declare (ignore initargs))
   (find-class 'structure-direct-slot-definition))
        (dolist (r (slot-definition-readers dslotd)) (fix r slot-name 'r))
        (dolist (w (slot-definition-writers dslotd)) (fix w slot-name 'w))))))
 \f
-(defun add-direct-subclasses (class new)
-  (dolist (n new)
+(defun add-direct-subclasses (class supers)
+  (dolist (super supers)
     (unless (memq class (class-direct-subclasses class))
-      (add-direct-subclass n class))))
+      (add-direct-subclass super class))))
 
-(defun remove-direct-subclasses (class new)
+(defun remove-direct-subclasses (class supers)
   (let ((old (class-direct-superclasses class)))
-    (dolist (o (set-difference old new))
+    (dolist (o (set-difference old supers))
       (remove-direct-subclass o class))))
 \f
 (defmethod finalize-inheritance ((class std-class))
 ;;; 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.
                   (make-wrapper nslots class))
                  ((and (equal nlayout olayout)
                        (not
-                        (iterate ((o (list-elements owrapper-class-slots))
-                                  (n (list-elements nwrapper-class-slots)))
-                                 (unless (eq (car o) (car n)) (return t)))))
+                         (loop for o in owrapper-class-slots
+                               for n in nwrapper-class-slots
+                               do (unless (eq (car o) (car n)) (return t)))))
                   owrapper)
                  (t
-                  ;; This will initialize the new wrapper to have the same
-                  ;; state as the old wrapper. We will then have to change
-                  ;; that. This may seem like wasted work (it is), but the
-                  ;; spec requires that we call make-instances-obsolete.
+                  ;; This will initialize the new wrapper to have the
+                  ;; same state as the old wrapper. We will then have
+                  ;; to change that. This may seem like wasted work
+                  ;; (and it is), but the spec requires that we call
+                  ;; MAKE-INSTANCES-OBSOLETE.
                   (make-instances-obsolete class)
                   (class-wrapper class)))))
 
        (update-pv-table-cache-info class)))))
 
 (defun compute-class-slots (eslotds)
-  (gathering1 (collecting)
+  (let (collect)
     (dolist (eslotd eslotds)
-      (gather1
-       (assoc (slot-definition-name eslotd)
-              (class-slot-cells (slot-definition-allocation eslotd)))))))
+      (push (assoc (slot-definition-name eslotd)
+                   (class-slot-cells (slot-definition-class eslotd)))
+            collect))
+    (nreverse collect)))
 
 (defun compute-layout (cpl instance-eslotds)
   (let* ((names
-          (gathering1 (collecting)
+          (let (collect)
             (dolist (eslotd instance-eslotds)
               (when (eq (slot-definition-allocation eslotd) :instance)
-                (gather1 (slot-definition-name eslotd))))))
+                (push (slot-definition-name eslotd) collect)))
+             (nreverse collect)))
         (order ()))
     (labels ((rwalk (tail)
               (when tail
                   (setf (gethash gf gf-table) t))
                 (mapc #'collect-gfs (class-direct-superclasses class))))
        (collect-gfs class)
-       (maphash #'(lambda (gf ignore)
-                    (declare (ignore ignore))
-                    (update-gf-dfun class gf))
+       (maphash (lambda (gf ignore)
+                  (declare (ignore ignore))
+                  (update-gf-dfun class gf))
                 gf-table)))))
 
 (defun update-inits (class inits)
            (if entry
                (push d (cdr entry))
                (push (list name d) name-dslotds-alist))))))
-    (mapcar #'(lambda (direct)
-               (compute-effective-slot-definition class
-                                                  (nreverse (cdr direct))))
+    (mapcar (lambda (direct)
+             (compute-effective-slot-definition class
+                                                (nreverse (cdr direct))))
            name-dslotds-alist)))
 
 (defmethod compute-slots :around ((class std-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)))))
     (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))
 
 (defmethod compute-slots ((class structure-class))
-  (mapcan #'(lambda (superclass)
-             (mapcar #'(lambda (dslotd)
-                         (compute-effective-slot-definition class
-                                                            (list dslotd)))
-                     (class-direct-slots superclass)))
+  (mapcan (lambda (superclass)
+           (mapcar (lambda (dslotd)
+                     (compute-effective-slot-definition class
+                                                        (list dslotd)))
+                   (class-direct-slots superclass)))
          (reverse (slot-value class 'class-precedence-list))))
 
 (defmethod compute-slots :around ((class structure-class))
   (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
-;;; *** for each possible type test. In order to do this it would be nice
-;;; *** to have help from inform-type-system-about-class and friends.
+;;; *** for each possible type test.
 ;;;
 ;;; *** 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
-;;; *** defined for this metclass a chance to run.
+;;; *** 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)
   (make-std-reader-method-function (class-name class) slot-name))
 (defmethod make-boundp-method-function ((class slot-class) slot-name)
   (make-std-boundp-method-function (class-name class) slot-name))
 \f
-;;;; inform-type-system-about-class
-;;;; make-type-predicate
-;;;
-;;; These are NOT part of the standard protocol. They are internal
-;;; mechanism which PCL uses to *try* and tell the type system about
-;;; class definitions. In a more fully integrated implementation of
-;;; CLOS, the type system would know about class objects and class
-;;; names in a more fundamental way and the mechanism used to inform
-;;; the type system about new classes would be different.
-(defmethod inform-type-system-about-class ((class std-class) name)
-  (inform-type-system-about-std-class name))
-\f
 (defmethod compatible-meta-class-change-p (class proto-new-class)
   (eq (class-of class) (class-of proto-new-class)))
 
     (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))
-        (state (wrapper-state owrapper)))
-    ;; 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
+  (let* ((owrapper (class-wrapper class)))
+    ;; 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)
        (sb-sys:without-interrupts
          (update-lisp-class-layout class nwrapper)
          (setf (slot-value class 'wrapper) nwrapper)
-         (invalidate-wrapper owrapper ':flush nwrapper))))))
+         (invalidate-wrapper owrapper :flush nwrapper))))))
 
 (defun flush-cache-trap (owrapper nwrapper instance)
   (declare (ignore owrapper))
   (set-wrapper instance nwrapper))
 \f
-;;; 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)
       (sb-sys:without-interrupts
        (update-lisp-class-layout class nwrapper)
        (setf (slot-value class 'wrapper) nwrapper)
-       (invalidate-wrapper owrapper ':obsolete nwrapper)
+       (invalidate-wrapper owrapper :obsolete nwrapper)
        class)))
 
 (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
 ;;;
 ;;; 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*
        ;;  --    --> shared    --
 
        ;; Go through all the old local slots.
-       (iterate ((name (list-elements olayout))
-                 (opos (interval :from 0)))
-         (let ((npos (posq name nlayout)))
-           (if npos
-               (setf (clos-slots-ref nslots npos)
-                     (clos-slots-ref oslots opos))
-               (progn
-                 (push name discarded)
-                 (unless (eq (clos-slots-ref oslots opos) +slot-unbound+)
-                   (setf (getf plist name) (clos-slots-ref oslots opos)))))))
+        (let ((opos 0))
+          (dolist (name olayout)
+            (let ((npos (posq name nlayout)))
+              (if npos
+                  (setf (clos-slots-ref nslots npos)
+                        (clos-slots-ref oslots opos))
+                  (progn
+                    (push name discarded)
+                    (unless (eq (clos-slots-ref oslots opos) +slot-unbound+)
+                      (setf (getf plist name) (clos-slots-ref oslots opos))))))
+            (incf opos)))
 
        ;; Go through all the old shared slots.
-       (iterate ((oclass-slot-and-val (list-elements oclass-slots)))
+        (dolist (oclass-slot-and-val oclass-slots)
          (let ((name (car oclass-slot-and-val))
                (val (cdr oclass-slot-and-val)))
            (let ((npos (posq name nlayout)))
                                             plist)
        nwrapper)))
 \f
-(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))
         (old-class-slots (wrapper-class-slots old-wrapper)))
 
     ;; "The values of local slots specified by both the class CTO and
-    ;; CFROM are retained. If such a local slot was unbound, it remains
-    ;; unbound."
-    (iterate ((new-slot (list-elements new-layout))
-             (new-position (interval :from 0)))
-      (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)))))
+    ;; CFROM are retained. If such a local slot was unbound, it
+    ;; remains unbound."
+    (let ((new-position 0))
+      (dolist (new-slot new-layout)
+        (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))))
+       (incf new-position)))
 
     ;; "The values of slots specified as shared in the class CFROM and
     ;; as local in the class CTO are retained."
-    (iterate ((slot-and-val (list-elements old-class-slots)))
+    (dolist (slot-and-val old-class-slots)
       (let ((position (posq (car slot-and-val) new-layout)))
        (when position
          (setf (clos-slots-ref new-slots position) (cdr slot-and-val)))))
     ;; 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))
 \f
 ;;;; The metaclass BUILT-IN-CLASS
 ;;;;
   (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)