X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fstd-class.lisp;h=910612f6b3ce46497b27a4666ed04ef04081f918;hb=2d3cb6dba6461e98744eca2a1df4f770cea468ca;hp=7b4c2933d8c234df790bb44fd84434e2ccf3b32e;hpb=63b936310ea60482b6903126d20a9b68f560de4c;p=sbcl.git diff --git a/src/pcl/std-class.lisp b/src/pcl/std-class.lisp index 7b4c293..910612f 100644 --- a/src/pcl/std-class.lisp +++ b/src/pcl/std-class.lisp @@ -320,13 +320,9 @@ :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 - ;; does not yet exist. Maybe should return NIL in that case as RES - ;; is not useful to the user? - (and (class-wrapper res) (sb-kernel:layout-class (class-wrapper res))))) + res)) (setf (gdefinition 'load-defclass) #'real-load-defclass) @@ -336,8 +332,10 @@ (defmethod ensure-class-using-class (name (class null) &rest args &key) (multiple-value-bind (meta initargs) (ensure-class-values class args) + (set-class-type-translation (class-prototype meta) name) (setf class (apply #'make-instance meta :name name initargs) (find-class name) class) + (set-class-type-translation class name) class)) (defmethod ensure-class-using-class (name (class pcl-class) &rest args &key) @@ -346,6 +344,7 @@ (unless (eq (class-of class) meta) (change-class class meta)) (apply #'reinitialize-instance class initargs) (setf (find-class name) class) + (set-class-type-translation class name) class)) (defmethod class-predicate-name ((class t)) @@ -382,34 +381,66 @@ ;; 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 + (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 "~@" + :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)))) - do (error 'simple-program-error - :format-control "Duplicate slot option ~S for slot ~S." - :format-arguments (list option slot-name)))) + (not (eq unsupplied + (getf more option unsupplied)))) + (error 'simple-program-error + :format-control "~@" + :format-arguments (list option slot-name))) + ((and (eq option :readers) + (notevery #'symbolp value)) + (error 'simple-program-error + :format-control "~@" + :format-arguments (list slot-name))) + ((and (eq option :initargs) + (notevery #'symbolp value)) + (error 'simple-program-error + :format-control "~@" + :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 of class ~A." + :format-control "~@" :format-arguments (list name class))) - (loop (unless (remf initargs :metaclass) (return))) + (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 "~@"))) + (:direct-default-initargs + (when (> (incf default-initargs) 1) + (error 'simple-program-error + :format-control "~@")))))) + (remf initargs :metaclass) (loop (unless (remf initargs :direct-superclasses) (return))) (loop (unless (remf initargs :direct-slots) (return))) (values meta @@ -499,10 +530,10 @@ (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)) +(defmethod shared-initialize :after + ((slotd structure-slot-definition) slot-names &key + (allocation :instance) allocation-class) + (declare (ignore slot-names allocation-class)) (unless (eq allocation :instance) (error "Structure slots must have :INSTANCE allocation."))) @@ -521,18 +552,14 @@ +slot-unbound+)) direct-slots))) (reader-names (mapcar (lambda (slotd) - (intern (format nil - "~A~A reader" - conc-name - (slot-definition-name - slotd)))) + (list 'slot-accessor name + (slot-definition-name slotd) + 'reader)) direct-slots)) (writer-names (mapcar (lambda (slotd) - (intern (format nil - "~A~A writer" - conc-name - (slot-definition-name - slotd)))) + (list 'slot-accessor name + (slot-definition-name slotd) + 'writer)) direct-slots)) (readers-init (mapcar (lambda (slotd reader-name) @@ -613,9 +640,9 @@ (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))) + (let ((lclass (sb-kernel:find-classoid (class-name class)))) + (setf (sb-kernel:classoid-pcl-class lclass) class) + (setf (slot-value class 'wrapper) (sb-kernel:classoid-layout lclass))) (update-pv-table-cache-info class) (setq predicate-name (if predicate-name-p (setf (slot-value class 'predicate-name) @@ -667,6 +694,17 @@ (defmethod finalize-inheritance ((class std-class)) (update-class class t)) + +(defmethod finalize-inheritance ((class forward-referenced-class)) + ;; FIXME: should we not be thinking a bit about what kinds of error + ;; we're throwing? Maybe we need a clos-error type to mix in? Or + ;; possibly a forward-referenced-class-error, though that's + ;; difficult given e.g. class precedence list calculations... + (error + "~@" + class)) + (defun class-has-a-forward-referenced-superclass-p (class) (or (forward-referenced-class-p class) @@ -697,7 +735,7 @@ (update-slots class (compute-slots class)) (update-gfs-of-class class) (update-inits class (compute-default-initargs class)) - (update-make-instance-function-table class)) + (update-ctors 'finalize-inheritance :class class)) (unless finalizep (dolist (sub (class-direct-subclasses class)) (update-class sub nil)))) @@ -778,27 +816,6 @@ collect)) (nreverse collect))) -(defun compute-layout (cpl instance-eslotds) - (let* ((names - (let (collect) - (dolist (eslotd instance-eslotds) - (when (eq (slot-definition-allocation eslotd) :instance) - (push (slot-definition-name eslotd) collect))) - (nreverse collect))) - (order ())) - (labels ((rwalk (tail) - (when tail - (rwalk (cdr tail)) - (dolist (ss (class-slots (car tail))) - (let ((n (slot-definition-name ss))) - (when (member n names) - (setq order (cons n order) - names (remove n names)))))))) - (rwalk (if (slot-boundp (car cpl) 'slots) - cpl - (cdr cpl))) - (reverse (append names order))))) - (defun update-gfs-of-class (class) (when (and (class-finalized-p class) (let ((cpl (class-precedence-list class))) @@ -852,38 +869,83 @@ ;; The list is in most-specific-first order. (let ((name-dslotds-alist ())) (dolist (c (class-precedence-list class)) - (let ((dslotds (class-direct-slots c))) - (dolist (d dslotds) - (let* ((name (slot-definition-name d)) - (entry (assq name name-dslotds-alist))) - (if entry - (push d (cdr entry)) - (push (list name d) name-dslotds-alist)))))) + (dolist (slot (class-direct-slots c)) + (let* ((name (slot-definition-name slot)) + (entry (assq name name-dslotds-alist))) + (if entry + (push slot (cdr entry)) + (push (list name slot) name-dslotds-alist))))) (mapcar (lambda (direct) (compute-effective-slot-definition class (nreverse (cdr direct)))) name-dslotds-alist))) -(defmethod compute-slots :around ((class std-class)) +(defmethod compute-slots ((class standard-class)) + (call-next-method)) + +(defmethod compute-slots :around ((class standard-class)) (let ((eslotds (call-next-method)) - (cpl (class-precedence-list class)) - (instance-slots ()) - (class-slots ())) - (dolist (eslotd eslotds) - (let ((alloc (slot-definition-allocation eslotd))) - (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) - (position (slot-definition-name eslotd) nlayout)))) - (dolist (eslotd class-slots) + (location -1)) + (dolist (eslotd eslotds eslotds) (setf (slot-definition-location eslotd) - (assoc (slot-definition-name eslotd) - (class-slot-cells (slot-definition-class eslotd))))) - (mapc #'initialize-internal-slot-functions eslotds) - eslotds)) + (ecase (slot-definition-allocation eslotd) + (:instance + (incf location)) + (:class + (let* ((name (slot-definition-name eslotd)) + (from-class (slot-definition-allocation-class eslotd)) + (cell (assq name (class-slot-cells from-class)))) + (aver (consp cell)) + cell)))) + (initialize-internal-slot-functions eslotd)))) + +(defmethod compute-slots ((class funcallable-standard-class)) + (call-next-method)) + +(defmethod compute-slots :around ((class funcallable-standard-class)) + (labels ((instance-slot-names (slotds) + (let (collect) + (dolist (slotd slotds (nreverse collect)) + (when (eq (slot-definition-allocation slotd) :instance) + (push (slot-definition-name slotd) collect))))) + ;; This sorts slots so that slots of classes later in the CPL + ;; come before slots of other classes. This is crucial for + ;; funcallable instances because it ensures that the slots of + ;; FUNCALLABLE-STANDARD-OBJECT, which includes the slots of + ;; KERNEL:FUNCALLABLE-INSTANCE, come first, which in turn + ;; makes it possible to treat FUNCALLABLE-STANDARD-OBJECT as + ;; a funcallable instance. + (compute-layout (eslotds) + (let ((first ()) + (names (instance-slot-names eslotds))) + (dolist (class + (reverse (class-precedence-list class)) + (nreverse (nconc names first))) + (dolist (ss (class-slots class)) + (let ((name (slot-definition-name ss))) + (when (member name names) + (push name first) + (setq names (delete name names))))))))) + (let ((all-slotds (call-next-method)) + (instance-slots ()) + (class-slots ())) + (dolist (slotd all-slotds) + (ecase (slot-definition-allocation slotd) + (:instance (push slotd instance-slots)) + (:class (push slotd class-slots)))) + (let ((layout (compute-layout instance-slots))) + (dolist (slotd instance-slots) + (setf (slot-definition-location slotd) + (position (slot-definition-name slotd) layout)) + (initialize-internal-slot-functions slotd))) + (dolist (slotd class-slots) + (let ((name (slot-definition-name slotd)) + (from-class (slot-definition-allocation-class slotd))) + (setf (slot-definition-location slotd) + (assoc name (class-slot-cells from-class))) + (aver (consp (slot-definition-location slotd))) + (initialize-internal-slot-functions slotd))) + all-slotds))) (defmethod compute-slots ((class structure-class)) (mapcan (lambda (superclass) @@ -918,6 +980,7 @@ (initform nil) (initargs nil) (allocation nil) + (allocation-class nil) (type t) (namep nil) (initp nil) @@ -935,6 +998,7 @@ initp t))) (unless allocp (setq allocation (slot-definition-allocation slotd) + allocation-class (slot-definition-class slotd) allocp t)) (setq initargs (append (slot-definition-initargs slotd) initargs)) (let ((slotd-type (slot-definition-type slotd))) @@ -946,6 +1010,7 @@ :initfunction initfunction :initargs initargs :allocation allocation + :allocation-class allocation-class :type type :class class))) @@ -1048,14 +1113,38 @@ (or (eq new-super-meta-class *the-class-std-class*) (eq (class-of class) new-super-meta-class)))) +;;; 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 ) or (:OBSOLETE ), 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 ); UPDATE-SLOTS later gets to choose whether or +;;; not to "upgrade" this to (:OBSOLETE ). +;;; +;;; 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) @@ -1282,6 +1371,17 @@ (or (eq s *the-class-t*) (eq s *the-class-stream*))) +;;; 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)