0.8alpha.0.3:
[sbcl.git] / src / pcl / std-class.lisp
index e6ab1cc..d943fb8 100644 (file)
        (compute-slot-accessor-info slotd type gf)))
     (initialize-internal-slot-gfs name)))
 
+;;; CMUCL (Gerd PCL 2003-04-25) comment:
+;;;
+;;; Compute an effective method for SLOT-VALUE-USING-CLASS, (SETF
+;;; SLOT-VALUE-USING-CLASS) or SLOT-BOUNDP-USING-CLASS for reading/
+;;; writing/testing effective slot SLOTD.
+;;;
+;;; TYPE is one of the symbols READER, WRITER or BOUNDP, depending on
+;;; GF.  Store the effective method in the effective slot definition
+;;; object itself; these GFs have special dispatch functions calling
+;;; effective methods directly retrieved from effective slot
+;;; definition objects, as an optimization.
+;;;
+;;; FIXME: Change the function name to COMPUTE-SVUC-SLOTD-FUNCTION,
+;;; or some such.
 (defmethod compute-slot-accessor-info ((slotd effective-slot-definition)
                                       type gf)
   (let* ((name (slot-value slotd 'name))
 ;;;; various class accessors that are a little more complicated than can be
 ;;;; done with automatically generated reader methods
 
-(defmethod class-finalized-p ((class pcl-class))
-  (with-slots (wrapper) class
-    (not (null wrapper))))
-
 (defmethod class-prototype ((class std-class))
   (with-slots (prototype) class
     (or prototype (setq prototype (allocate-instance class)))))
 (setf (gdefinition 'load-defclass) #'real-load-defclass)
 
 (defun ensure-class (name &rest all)
-  (apply #'ensure-class-using-class name (find-class name nil) all))
+  (apply #'ensure-class-using-class (find-class name nil) name all))
 
-(defmethod ensure-class-using-class (name (class null) &rest args &key)
+(defmethod ensure-class-using-class ((class null) name &rest args &key)
   (multiple-value-bind (meta initargs)
       (ensure-class-values class args)
     (set-class-type-translation (class-prototype meta) name)
     (set-class-type-translation class name)
     class))
 
-(defmethod ensure-class-using-class (name (class pcl-class) &rest args &key)
+(defmethod ensure-class-using-class ((class pcl-class) name &rest args &key)
   (multiple-value-bind (meta initargs)
       (ensure-class-values class args)
-    (unless (eq (class-of class) meta) (change-class class meta))
+    (unless (eq (class-of class) meta)
+      (apply #'change-class class meta initargs))
     (apply #'reinitialize-instance class initargs)
     (setf (find-class name) class)
     (set-class-type-translation class name)
 (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))
+        (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))))))
+        (or (find-class s nil)
+            (make-instance 'forward-referenced-class
+                           :name s)))))
 
 (defun ensure-class-values (class args)
   (let* ((initargs (copy-list args))
     (remf initargs :metaclass)
     (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))))
+    (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))))
 \f
-
 (defmethod shared-initialize :after
           ((class std-class)
            slot-names
                                     (make-class-predicate-name (class-name
                                                                 class))))))
   (add-direct-subclasses class direct-superclasses)
-  (update-class class nil)
   (make-class-predicate class predicate-name)
-  (add-slot-accessors class direct-slots))
+  (update-class class nil)
+  (do* ((slots (slot-value class 'slots) (cdr slots))
+       (dupes nil))
+       ((null slots) (when dupes
+                      (style-warn
+                       ;; FIXME: the indentation request ("~4I")
+                       ;; below appears not to do anything.  Finding
+                       ;; out why would be nice.  -- CSR, 2003-04-24
+                       "~@<slot names with the same SYMBOL-NAME but ~
+                         different SYMBOL-PACKAGE (possible package problem) ~
+                         for class ~S:~@:_~4I~<~@{~S~^~:@_~}~:>~@:>"
+                       class
+                       dupes)))
+    (let* ((slot (car slots))
+          (oslots (remove (slot-definition-name slot) (cdr slots)
+                          :test-not #'string= :key #'slot-definition-name)))
+      (when oslots
+       (pushnew (cons (slot-definition-name slot)
+                      (mapcar #'slot-definition-name oslots))
+                dupes
+                :test #'string= :key #'car))))
+  (add-slot-accessors class direct-slots)
+  (make-preliminary-layout class))
+
+(defmethod shared-initialize :after ((class forward-referenced-class)
+                                    slot-names &key &allow-other-keys)
+  (declare (ignore slot-names))
+  (make-preliminary-layout class))
+
+(defvar *allow-forward-referenced-classes-in-cpl-p* nil)
+
+;;; Give CLASS a preliminary layout if it doesn't have one already, to
+;;; make it known to the type system.
+(defun make-preliminary-layout (class)
+  (flet ((compute-preliminary-cpl (root)
+          (let ((*allow-forward-referenced-classes-in-cpl-p* t))
+            (compute-class-precedence-list root))))
+    (unless (class-finalized-p class)
+      (let ((name (class-name class)))
+       (setf (find-class name) class)
+       ;; KLUDGE: This is fairly horrible.  We need to make a
+       ;; full-fledged CLASSOID here, not just tell the compiler that
+       ;; some class is forthcoming, because there are legitimate
+       ;; questions one can ask of the type system, implemented in
+       ;; terms of CLASSOIDs, involving forward-referenced classes. So.
+       (when (and (eq *boot-state* 'complete)
+                  (null (find-classoid name nil)))
+         (setf (find-classoid name)
+               (make-standard-classoid :name name)))
+       (set-class-type-translation class name)
+       (let ((layout (make-wrapper 0 class))
+             (classoid (find-classoid name)))
+         (setf (layout-classoid layout) classoid)
+         (setf (classoid-pcl-class classoid) class)
+         (setf (slot-value class 'wrapper) layout)
+         (let ((cpl (compute-preliminary-cpl class)))
+           (setf (layout-inherits layout)
+                 (order-layout-inherits
+                  (map 'simple-vector #'class-wrapper
+                       (reverse (rest cpl))))))
+         (register-layout layout :invalidate t)
+         (setf (classoid-layout classoid) layout)
+         (mapc #'make-preliminary-layout (class-direct-subclasses class)))))))
+
 
 (defmethod shared-initialize :before ((class class) slot-names &key name)
   (declare (ignore slot-names name))
                  (lambda (dependent)
                    (apply #'update-dependent class dependent initargs))))
 
+(defmethod shared-initialize :after ((class condition-class) slot-names
+                                    &key direct-superclasses)
+  (declare (ignore slot-names))
+  (let ((classoid (find-classoid (class-name class))))
+    (with-slots (wrapper class-precedence-list prototype predicate-name
+                        (direct-supers direct-superclasses))
+       class
+      (setf (slot-value class 'finalized-p) t)
+      (setf (classoid-pcl-class classoid) class)
+      (setq direct-supers direct-superclasses)
+      (setq wrapper (classoid-layout classoid))
+      (setq class-precedence-list (compute-class-precedence-list class))
+      (setq prototype (make-condition (class-name class)))
+      (add-direct-subclasses class direct-superclasses)
+      (setq predicate-name (make-class-predicate-name (class-name class)))
+      (make-class-predicate class predicate-name))))
+
 (defmethod shared-initialize :after
     ((slotd structure-slot-definition) slot-names &key
      (allocation :instance) allocation-class)
     (let ((lclass (find-classoid (class-name class))))
       (setf (classoid-pcl-class lclass) class)
       (setf (slot-value class 'wrapper) (classoid-layout lclass)))
+    (setf (slot-value class 'finalized-p) t)
     (update-pv-table-cache-info class)
     (setq predicate-name (if predicate-name-p
                           (setf (slot-value 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)
+
+(defmethod direct-slot-definition-class ((class structure-class) &rest initargs)
   (declare (ignore initargs))
   (find-class 'structure-direct-slot-definition))
 
     (return-from update-class))
   (when (or finalizep (class-finalized-p class)
            (not (class-has-a-forward-referenced-superclass-p class)))
+    (setf (find-class (class-name class)) 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
                                  :key #'slot-definition-location)))
           (nslots (length nlayout))
           (nwrapper-class-slots (compute-class-slots class-slots))
-          (owrapper (class-wrapper class))
-          (olayout (and owrapper (wrapper-instance-slots-layout owrapper)))
+          (owrapper (when (class-finalized-p class)
+                      (class-wrapper class)))
+          (olayout (when owrapper
+                     (wrapper-instance-slots-layout owrapper)))
           (owrapper-class-slots (and owrapper (wrapper-class-slots owrapper)))
           (nwrapper
            (cond ((null owrapper)
              (wrapper-class-slots nwrapper) nwrapper-class-slots
              (wrapper-no-of-instance-slots nwrapper) nslots
              wrapper nwrapper))
-
+      (setf (slot-value class 'finalized-p) t)
       (unless (eq owrapper nwrapper)
        (update-pv-table-cache-info class)))))
 
   (setf (plist-value class 'default-initargs) inits))
 \f
 (defmethod compute-default-initargs ((class slot-class))
-  (let ((cpl (class-precedence-list class))
-       (direct (class-direct-default-initargs class)))
-    (labels ((walk (tail)
-              (if (null tail)
-                  nil
-                  (let ((c (pop tail)))
-                    (append (if (eq c class)
-                                direct
-                                (class-direct-default-initargs c))
-                            (walk tail))))))
-      (let ((initargs (walk cpl)))
-       (delete-duplicates initargs :test #'eq :key #'car :from-end t)))))
+  (let ((initargs (loop for c in (class-precedence-list class)
+                       append (class-direct-default-initargs c))))
+    (delete-duplicates initargs :test #'eq :key #'car :from-end t)))
 \f
 ;;;; protocols for constructing direct and effective slot definitions
 
-(defmethod direct-slot-definition-class ((class std-class) initargs)
+(defmethod direct-slot-definition-class ((class std-class) &rest initargs)
   (declare (ignore initargs))
   (find-class 'standard-direct-slot-definition))
 
 (defun make-direct-slotd (class initargs)
   (let ((initargs (list* :class class initargs)))
     (apply #'make-instance
-          (direct-slot-definition-class class initargs)
+          (apply #'direct-slot-definition-class class initargs)
           initargs)))
 
 (defmethod compute-slots ((class std-class))
              (push (list name slot) name-dslotds-alist)))))
     (mapcar (lambda (direct)
              (compute-effective-slot-definition class
+                                                (car direct)
                                                 (nreverse (cdr direct))))
            name-dslotds-alist)))
 
 (defmethod compute-slots ((class structure-class))
   (mapcan (lambda (superclass)
            (mapcar (lambda (dslotd)
-                     (compute-effective-slot-definition class
-                                                        (list dslotd)))
+                     (compute-effective-slot-definition
+                      class
+                      (slot-definition-name dslotd)
+                      (list dslotd)))
                    (class-direct-slots superclass)))
          (reverse (slot-value class 'class-precedence-list))))
 
     (mapc #'initialize-internal-slot-functions eslotds)
     eslotds))
 
-(defmethod compute-effective-slot-definition ((class slot-class) dslotds)
+(defmethod compute-effective-slot-definition ((class slot-class) name dslotds)
+  (declare (ignore name))
   (let* ((initargs (compute-effective-slot-definition-initargs class dslotds))
-        (class (effective-slot-definition-class class initargs)))
+        (class (apply #'effective-slot-definition-class class initargs)))
     (apply #'make-instance class initargs)))
 
-(defmethod effective-slot-definition-class ((class std-class) initargs)
+(defmethod effective-slot-definition-class ((class std-class) &rest initargs)
   (declare (ignore initargs))
   (find-class 'standard-effective-slot-definition))
 
-(defmethod effective-slot-definition-class ((class structure-class) initargs)
+(defmethod effective-slot-definition-class ((class structure-class) &rest initargs)
   (declare (ignore initargs))
   (find-class 'structure-effective-slot-definition))
 
              (wrapper-instance-slots-layout owrapper))
        (setf (wrapper-class-slots nwrapper)
              (wrapper-class-slots owrapper))
-       (sb-sys:without-interrupts
+       (with-pcl-lock
          (update-lisp-class-layout class nwrapper)
          (setf (slot-value class 'wrapper) nwrapper)
          (invalidate-wrapper owrapper :flush nwrapper))))))
            (wrapper-instance-slots-layout owrapper))
       (setf (wrapper-class-slots nwrapper)
            (wrapper-class-slots owrapper))
-      (sb-sys:without-interrupts
+      (with-pcl-lock
        (update-lisp-class-layout class nwrapper)
        (setf (slot-value class 'wrapper) nwrapper)
        (invalidate-wrapper owrapper :obsolete nwrapper)