0.7.12.1:
[sbcl.git] / src / code / defstruct.lisp
index 8a0eb70..2a7cebe 100644 (file)
             (:copier nil)
             #-sb-xc-host (:pure t))
   ;; string name of slot
-  %name        
+  %name
   ;; its position in the implementation sequence
   (index (missing-arg) :type fixnum)
   ;; the name of the accessor function
   (accessor-name nil)
   default                      ; default value expression
   (type t)                     ; declared type specifier
+  (safe-p t :type boolean)      ; whether the slot is known to be
+                                ; always of the specified type
   ;; If this object does not describe a raw slot, this value is T.
   ;;
   ;; If this object describes a raw slot, this value is the type of the
     ;; What operator is used (on the raw data vector) to access a slot
     ;; of this type?
     (accessor-name (missing-arg) :type symbol :read-only t)
-    ;; How many words are each value of this type? (This is used to 
+    ;; How many words are each value of this type? (This is used to
     ;; rescale the offset into the raw data vector.)
     (n-words (missing-arg) :type (and index (integer 1)) :read-only t))
 
-  (defvar *raw-slot-data-list* 
+  (defvar *raw-slot-data-list*
     (list
      ;; The compiler thinks that the raw data vector is a vector of
      ;; word-sized unsigned bytes, so if the slot we want to access
     (setf (dsd-%name slot) (string name))
     (setf (dd-slots defstruct) (nconc (dd-slots defstruct) (list slot)))
 
-    (let ((accessor-name (symbolicate (or (dd-conc-name defstruct) "") name))
+    (let ((accessor-name (if (dd-conc-name defstruct)
+                            (symbolicate (dd-conc-name defstruct) name)
+                            name))
          (predicate-name (dd-predicate-name defstruct)))
       (setf (dsd-accessor-name slot) accessor-name)
       (when (eql accessor-name predicate-name)
 ;;; and writer functions of the slot described by DSD.
 (defun slot-accessor-inline-expansion-designators (dd dsd)
   (let ((instance-type-decl `(declare (type ,(dd-name dd) instance)))
-       (accessor-place-form (%accessor-place-form dd dsd 'instance))
-       (dsd-type (dsd-type dsd)))
-    (values (lambda ()
-             `(lambda (instance)
-                ,instance-type-decl
-                (truly-the ,dsd-type ,accessor-place-form)))
-           (lambda ()
-             `(lambda (new-value instance)
-                (declare (type ,dsd-type new-value))
-                ,instance-type-decl
-                (setf ,accessor-place-form new-value))))))
+        (accessor-place-form (%accessor-place-form dd dsd 'instance))
+        (dsd-type (dsd-type dsd))
+        (value-the (if (dsd-safe-p dsd) 'truly-the 'the)))
+    (values (lambda () `(lambda (instance)
+                          ,instance-type-decl
+                          (,value-the ,dsd-type ,accessor-place-form)))
+           (lambda () `(lambda (new-value instance)
+                          (declare (type ,dsd-type new-value))
+                          ,instance-type-decl
+                          (setf ,accessor-place-form new-value))))))
 
 ;;; Return a LAMBDA form which can be used to set a slot.
 (defun slot-setter-lambda-form (dd dsd)
 ;;;     structures can have arbitrary subtypes of VECTOR, not necessarily
 ;;;     SIMPLE-VECTOR.)
 ;;;   * STRUCTURE structures can have raw slots that must also be
-;;;     allocated and indirectly referenced. 
+;;;     allocated and indirectly referenced.
 (defun create-vector-constructor (dd cons-name arglist vars types values)
   (let ((temp (gensym))
        (etype (dd-element-type dd)))
                     `(setf (aref ,temp ,(cdr x))  ',(car x)))
                   (find-name-indices dd))
         ,@(mapcar (lambda (dsd value)
-                    `(setf (aref ,temp ,(dsd-index dsd)) ,value))
+                    (unless (eq value '.do-not-initialize-slot.)
+                         `(setf (aref ,temp ,(dsd-index dsd)) ,value)))
                   (dd-slots dd) values)
         ,temp))))
 (defun create-list-constructor (dd cons-name arglist vars types values)
     (dolist (x (find-name-indices dd))
       (setf (elt vals (cdr x)) `',(car x)))
     (loop for dsd in (dd-slots dd) and val in values do
-      (setf (elt vals (dsd-index dsd)) val))
+      (setf (elt vals (dsd-index dsd))
+            (if (eq val '.do-not-initialize-slot.) 0 val)))
 
     `(defun ,cons-name ,arglist
        (declare ,@(mapcar (lambda (var type) `(type ,type ,var)) vars types))
                     ;; because the slot might be :READ-ONLY, so we
                     ;; whip up new LAMBDA representations of slot
                     ;; setters for the occasion.)
-                    `(,(slot-setter-lambda-form dd dsd) ,value ,instance))
+                     (unless (eq value '.do-not-initialize-slot.)
+                       `(,(slot-setter-lambda-form dd dsd) ,value ,instance)))
                   (dd-slots dd)
                   values)
         ,instance))))
       (parse-lambda-list (second boa))
     (collect ((arglist)
              (vars)
-             (types))
+             (types)
+              (skipped-vars))
       (labels ((get-slot (name)
                 (let ((res (find name (dd-slots defstruct)
                                  :test #'string=
          (arglist arg)
          (vars arg)
          (types (get-slot arg)))
-       
+
        (when opt
          (arglist '&optional)
          (dolist (arg opt)
        (when auxp
          (arglist '&aux)
          (dolist (arg aux)
-           (let* ((arg (if (consp arg) arg (list arg)))
-                  (var (first arg)))
-             (arglist arg)
-             (vars var)
-             (types (get-slot var))))))
+            (arglist arg)
+            (if (proper-list-of-length-p arg 2)
+              (let ((var (first arg)))
+                (vars var)
+                (types (get-slot var)))
+              (skipped-vars (if (consp arg) (first arg) arg))))))
 
       (funcall creator defstruct (first boa)
               (arglist) (vars) (types)
-              (mapcar (lambda (slot)
-                        (or (find (dsd-name slot) (vars) :test #'string=)
-                            (dsd-default slot)))
-                      (dd-slots defstruct))))))
+               (loop for slot in (dd-slots defstruct)
+                     for name = (dsd-name slot)
+                     collect (cond ((find name (skipped-vars) :test #'string=)
+                                    (setf (dsd-safe-p slot) nil)
+                                    '.do-not-initialize-slot.)
+                                   ((or (find (dsd-name slot) (vars) :test #'string=)
+                                        (dsd-default slot)))))))))
 
 ;;; Grovel the constructor options, and decide what constructors (if
 ;;; any) to create.
 ;;;; main DEFSTRUCT macro. Hopefully it will go away presently
 ;;;; (perhaps when CL:CLASS and SB-PCL:CLASS meet) as per FIXME below.
 ;;;; -- WHN 2001-10-28
-;;;; 
+;;;;
 ;;;; FIXME: There seems to be no good reason to shoehorn CONDITION,
 ;;;; STANDARD-INSTANCE, and GENERIC-FUNCTION into mutated structures
 ;;;; instead of just implementing them as primitive objects. (This
                                  ,slot-name)))
                       slot-names)
             ,object-gensym))
-                             
+
         ;; predicate
         ,@(when predicate
             ;; Just delegate to the compiler's type optimization