X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fstd-class.lisp;h=41b439009d258a0f492023543ea53ea8642dbdfa;hb=f3f677703e37f5a335b3be7fa64f7748ad969517;hp=cec50b1581688c224055656cea9f3a68d8b38ab3;hpb=67dc5cf478dfe5e3f517001febb9a8f7b922eacf;p=sbcl.git diff --git a/src/pcl/std-class.lisp b/src/pcl/std-class.lisp index cec50b1..41b4390 100644 --- a/src/pcl/std-class.lisp +++ b/src/pcl/std-class.lisp @@ -121,21 +121,21 @@ ;;;; 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)) @@ -290,7 +290,6 @@ (setf (info :type :translator specl) (constantly (make-member-type :members (list (specializer-object specl)))))) - (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") @@ -347,97 +346,26 @@ (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 "~@" - :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 "~@" - :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 "~@" - :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 "~@"))) - (: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 - (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 + (if (classp metaclass) + metaclass + (find-class metaclass))) + ((or (null class) (forward-referenced-class-p class)) + *the-class-standard-class*) + (t + (class-of class))) + (nreverse reversed-plist)))) + (defmethod shared-initialize :after ((class std-class) @@ -575,8 +503,9 @@ (setf (slot-value class 'class-eq-specializer) (make-instance 'class-eq-specializer :class class))) -(defmethod reinitialize-instance :before ((class slot-class) &key) - (remove-direct-subclasses class (class-direct-superclasses class)) +(defmethod reinitialize-instance :before ((class slot-class) &key direct-superclasses) + (dolist (old-super (set-difference (class-direct-superclasses class) direct-superclasses)) + (remove-direct-subclass old-super class)) (remove-slot-accessors class (class-direct-slots class))) (defmethod reinitialize-instance :after ((class slot-class) @@ -721,15 +650,8 @@ (defun make-defstruct-allocation-function (class) (let ((dd (get-structure-dd (class-name class)))) (lambda () - (let ((instance (%make-instance (dd-length dd))) - (raw-index (dd-raw-index dd))) - (setf (%instance-layout instance) - (sb-kernel::compiler-layout-or-lose (dd-name dd))) - (when raw-index - (setf (%instance-ref instance raw-index) - (make-array (dd-raw-length dd) - :element-type '(unsigned-byte 32)))) - instance)))) + (sb-kernel::%make-instance-with-layout + (sb-kernel::compiler-layout-or-lose (dd-name dd)))))) (defmethod shared-initialize :after ((class structure-class) @@ -817,20 +739,26 @@ (defun fix-slot-accessors (class dslotds add/remove) (flet ((fix (gfspec name r/w) - (let ((gf (if (fboundp gfspec) - (without-package-locks - (ensure-generic-function gfspec)) - (ensure-generic-function - gfspec :lambda-list (case r/w - (r '(object)) - (w '(new-value object))))))) - (case r/w - (r (if (eq add/remove 'add) - (add-reader-method class gf name) - (remove-reader-method class gf))) - (w (if (eq add/remove 'add) - (add-writer-method class gf name) - (remove-writer-method class gf))))))) + (let ((gf (cond ((eq add/remove 'add) + (if (fboundp gfspec) + (without-package-locks + (ensure-generic-function gfspec)) + (ensure-generic-function + gfspec :lambda-list (case r/w + (r '(object)) + (w '(new-value object)))))) + ((generic-function-p (and (fboundp gfspec) + (fdefinition gfspec))) + (without-package-locks + (ensure-generic-function gfspec)))))) + (when gf + (case r/w + (r (if (eq add/remove 'add) + (add-reader-method class gf name) + (remove-reader-method class gf))) + (w (if (eq add/remove 'add) + (add-writer-method class gf name) + (remove-writer-method class gf)))))))) (dolist (dslotd dslotds) (let ((slot-name (slot-definition-name dslotd))) (dolist (r (slot-definition-readers dslotd)) @@ -843,11 +771,6 @@ (unless (memq class (class-direct-subclasses class)) (add-direct-subclass super class)))) -(defun remove-direct-subclasses (class supers) - (let ((old (class-direct-superclasses class))) - (dolist (o (set-difference old supers)) - (remove-direct-subclass o class)))) - (defmethod finalize-inheritance ((class std-class)) (update-class class t)) @@ -1016,18 +939,26 @@ (find-class 'standard-direct-slot-definition)) (defun make-direct-slotd (class initargs) - (let ((initargs (list* :class class initargs))) - (apply #'make-instance - (apply #'direct-slot-definition-class class initargs) - initargs))) - + (apply #'make-instance + (apply #'direct-slot-definition-class class initargs) + :class class + initargs)) + +;;; I (CSR) am not sure, but I believe that the particular order of +;;; slots is quite important: it is ideal to attempt to have a +;;; constant slot location for the same notional slots as much as +;;; possible, so that clever discriminating functions (ONE-INDEX et +;;; al.) have a chance of working. The below at least walks through +;;; the slots predictably, but maybe it would be good to compute some +;;; kind of optimal slot layout by looking at locations of slots in +;;; superclasses? (defmethod compute-slots ((class std-class)) ;; As specified, we must call COMPUTE-EFFECTIVE-SLOT-DEFINITION once ;; for each different slot name we find in our superclasses. Each ;; call receives the class and a list of the dslotds with that name. ;; The list is in most-specific-first order. (let ((name-dslotds-alist ())) - (dolist (c (class-precedence-list class)) + (dolist (c (reverse (class-precedence-list class))) (dolist (slot (class-direct-slots c)) (let* ((name (slot-definition-name slot)) (entry (assq name name-dslotds-alist))) @@ -1037,8 +968,8 @@ (mapcar (lambda (direct) (compute-effective-slot-definition class (car direct) - (nreverse (cdr direct)))) - name-dslotds-alist))) + (cdr direct))) + (nreverse name-dslotds-alist)))) (defmethod compute-slots ((class standard-class)) (call-next-method)) @@ -1567,8 +1498,12 @@ (defmethod class-default-initargs ((class built-in-class)) ()) (defmethod validate-superclass ((c class) (s built-in-class)) - (or (eq s *the-class-t*) - (eq s *the-class-stream*))) + (or (eq s *the-class-t*) (eq s *the-class-stream*) + ;; FIXME: bad things happen if someone tries to mix in both + ;; FILE-STREAM and STRING-STREAM (as they have the same + ;; layout-depthoid). Is there any way we can provide a useful + ;; error message? -- CSR, 2005-05-03 + (eq s *the-class-file-stream*) (eq s *the-class-string-stream*))) ;;; Some necessary methods for FORWARD-REFERENCED-CLASS (defmethod class-direct-slots ((class forward-referenced-class)) ())