0.8.1.25:
[sbcl.git] / src / code / early-type.lisp
index 77698dd..048b61a 100644 (file)
   (allowp nil :type boolean))
 
 (defun canonicalize-args-type-args (required optional rest)
-  (when rest
-    (let ((last-distinct-optional (position rest optional
-                                           :from-end t
-                                           :test-not #'type=)))
-      (setf optional
-           (when last-distinct-optional
-             (subseq optional 0 (1+ last-distinct-optional))))))
-  (values required optional rest))
+  (when (eq rest *empty-type*)
+    ;; or vice-versa?
+    (setq rest nil))
+  (loop with last-not-rest = nil
+        for i from 0
+        for opt in optional
+        do (cond ((eq opt *empty-type*)
+                  (return (values required (subseq optional i) rest)))
+                 ((neq opt rest)
+                  (setq last-not-rest i)))
+        finally (return (values required
+                                (if last-not-rest
+                                    (subseq optional 0 (1+ last-not-rest))
+                                    nil)
+                                rest))))
 
 (defun args-types (lambda-list-like-thing)
   (multiple-value-bind
-       (required optional restp rest keyp keys allowp auxp aux)
+       (required optional restp rest keyp keys allowp auxp aux
+                  morep more-context more-count llk-p)
       (parse-lambda-list-like-thing lambda-list-like-thing)
-    (declare (ignore aux))
+    (declare (ignore aux morep more-context more-count))
     (when auxp
       (error "&AUX in a FUNCTION or VALUES type: ~S." lambda-list-like-thing))
     (let ((required (mapcar #'single-value-specifier-type required))
             (key-info))))
       (multiple-value-bind (required optional rest)
          (canonicalize-args-type-args required optional rest)
-       (values required optional rest keyp keywords allowp)))))
-                   
+       (values required optional rest keyp keywords allowp llk-p)))))
+
 (defstruct (values-type
            (:include args-type
                      (class-info (type-class-or-lose 'values)))
             (:constructor %make-values-type)
            (:copier nil)))
 
-(defun make-values-type (&rest initargs
-                        &key (args nil argsp) &allow-other-keys)
+(defun-cached (make-values-type-cached
+               :hash-bits 8
+               :hash-function (lambda (req opt rest allowp)
+                                (logand (logxor
+                                         (type-list-cache-hash req)
+                                         (type-list-cache-hash opt)
+                                         (if rest
+                                             (type-hash-value rest)
+                                             42)
+                                         (sxhash allowp))
+                                        #xFF)))
+    ((required equal-but-no-car-recursion)
+     (optional equal-but-no-car-recursion)
+     (rest eq)
+     (allowp eq))
+  (%make-values-type :required required
+                     :optional optional
+                     :rest rest
+                     :allowp allowp))
+
+;;; FIXME: ANSI VALUES has a short form (without lambda list
+;;; keywords), which should be translated into a long one.
+(defun make-values-type (&key (args nil argsp)
+                         required optional rest allowp)
   (if argsp
       (if (eq args '*)
          *wild-type*
-         (multiple-value-bind (required optional rest keyp keywords allowp)
+         (multiple-value-bind (required optional rest keyp keywords allowp
+                                llk-p)
              (args-types args)
-           (if (and (null required)
-                    (null optional)
-                    (eq rest *universal-type*)
-                    (not keyp))
-               *wild-type*
-               (%make-values-type :required required
-                                  :optional optional
-                                  :rest rest
-                                  :keyp keyp
-                                  :keywords keywords
-                                  :allowp allowp))))
-      (apply #'%make-values-type initargs)))
+            (declare (ignore keywords))
+            (when keyp
+              (error "&KEY appeared in a VALUES type specifier ~S."
+                     `(values ,@args)))
+            (if llk-p
+                (make-values-type :required required
+                                  :optional optional
+                                  :rest rest
+                                  :allowp allowp)
+                (make-short-values-type required))))
+      (multiple-value-bind (required optional rest)
+          (canonicalize-args-type-args required optional rest)
+        (cond ((and (null required)
+                    (null optional)
+                    (eq rest *universal-type*))
+               *wild-type*)
+              ((memq *empty-type* required)
+               *empty-type*)
+              (t (make-values-type-cached required optional
+                                          rest allowp))))))
 
 (!define-type-class values)
 
 ;;; (SPECIFIER-TYPE 'FUNCTION) and its subtypes
 (defstruct (fun-type (:include args-type
                               (class-info (type-class-or-lose 'function)))
-                    (:constructor %make-fun-type))
+                     (:constructor
+                      %make-fun-type (&key required optional rest
+                                           keyp keywords allowp
+                                           wild-args
+                                           returns
+                                      &aux (rest (if (eq rest *empty-type*)
+                                                     nil
+                                                     rest)))))
   ;; true if the arguments are unrestrictive, i.e. *
   (wild-args nil :type boolean)
   ;; type describing the return values. This is a values type
   ;; canonicalize to (DOUBLE-FLOAT 0.0d0 0.0d0), because numeric
   ;; ranges are compared by arithmetic operators (while MEMBERship is
   ;; compared by EQL).  -- CSR, 2003-04-23
-  (let ((singlep (subsetp '(-0.0f0 0.0f0) members))
-       (doublep (subsetp '(-0.0d0 0.0d0) members))
+  (let ((singlep (subsetp `(,(load-time-value (make-unportable-float :single-float-negative-zero)) 0.0f0) members))
+       (doublep (subsetp `(,(load-time-value (make-unportable-float :double-float-negative-zero)) 0.0d0) members))
        #!+long-float
-       (longp (subsetp '(-0.0l0 0.0l0) members)))
+       (longp (subsetp `(,(load-time-value (make-unportable-float :long-float-negative-zero)) 0.0l0) members)))
     (if (or singlep doublep #!+long-float longp)
        (let (union-types)
          (when singlep
            (push (ctype-of 0.0f0) union-types)
-           (setf members (set-difference members '(-0.0f0 0.0f0))))
+           (setf members (set-difference members `(,(load-time-value (make-unportable-float :single-float-negative-zero)) 0.0f0))))
          (when doublep
            (push (ctype-of 0.0d0) union-types)
-           (setf members (set-difference members '(-0.0d0 0.0d0))))
+           (setf members (set-difference members `(,(load-time-value (make-unportable-float :double-float-negative-zero)) 0.0d0))))
          #!+long-float
          (when longp
            (push (ctype-of 0.0l0) union-types)
-           (setf members (set-difference members '(-0.0l0 0.0l0))))
+           (setf members (set-difference members `(,(load-time-value (make-unportable-float :long-float-negative-zero)) 0.0l0))))
          (aver (not (null union-types)))
          (make-union-type t
                           (if (null members)
 ;;; A CONS-TYPE is used to represent a CONS type.
 (defstruct (cons-type (:include ctype (class-info (type-class-or-lose 'cons)))
                      (:constructor
-                      ;; ANSI says that for CAR and CDR subtype
-                      ;; specifiers '* is equivalent to T. In order
-                      ;; to avoid special cases in SUBTYPEP and
-                      ;; possibly elsewhere, we slam all CONS-TYPE
-                      ;; objects into canonical form w.r.t. this
-                      ;; equivalence at creation time.
-                      %make-cons-type (car-raw-type
-                                       cdr-raw-type
-                                       &aux
-                                       (car-type (type-*-to-t car-raw-type))
-                                       (cdr-type (type-*-to-t cdr-raw-type))))
+                      %make-cons-type (car-type
+                                       cdr-type))
                      (:copier nil))
   ;; the CAR and CDR element types (to support ANSI (CONS FOO BAR) types)
   ;;
   (car-type (missing-arg) :type ctype :read-only t)
   (cdr-type (missing-arg) :type ctype :read-only t))
 (defun make-cons-type (car-type cdr-type)
+  (aver (not (or (eq car-type *wild-type*)
+                 (eq cdr-type *wild-type*))))
   (if (or (eq car-type *empty-type*)
          (eq cdr-type *empty-type*))
       *empty-type*
                (or (built-in-classoid-translation spec) spec)
                spec))
           (t
-           (let* (;; FIXME: This automatic promotion of FOO-style
-                  ;; specs to (FOO)-style specs violates the ANSI
-                  ;; standard. Unfortunately, we can't fix the
-                  ;; problem just by removing it, since then things
-                  ;; downstream should break. But at some point we
-                  ;; should fix this and the things downstream too.
-                  (lspec (if (atom spec) (list spec) spec))
+           (when (and (atom spec)
+                      (member spec '(and or not member eql satisfies values)))
+             (error "The symbol ~S is not valid as a type specifier." spec))
+           (let* ((lspec (if (atom spec) (list spec) spec))
                   (fun (info :type :translator (car lspec))))
              (cond (fun
                     (funcall fun lspec))
 ;;; never return a VALUES type.
 (defun specifier-type (x)
   (let ((res (values-specifier-type x)))
-    (when (values-type-p res)
+    (when (or (values-type-p res)
+              ;; bootstrap magic :-(
+              (and (named-type-p res)
+                   (eq (named-type-name res) '*)))
       (error "VALUES type illegal in this context:~%  ~S" x))
     res))
 
 (defun single-value-specifier-type (x)
-  (let ((res (specifier-type x)))
-    (if (eq res *wild-type*)
-        *universal-type*
-        res)))
+  (if (eq x '*)
+      *universal-type*
+      (specifier-type x)))
 
 ;;; Similar to MACROEXPAND, but expands DEFTYPEs. We don't bother
 ;;; returning a second value.
   (when (boundp 'sb!kernel::*values-specifier-type-cache-vector*)
     (values-specifier-type-cache-clear))
   (values))
+
 \f
 (!defun-from-collected-cold-init-forms !early-type-cold-init)