0.pre8.98:
[sbcl.git] / src / code / late-type.lisp
index 0feadf6..e4a17df 100644 (file)
 
 ;;; ### Remaining incorrectnesses:
 ;;;
-;;; TYPE-UNION (and the OR type) doesn't properly canonicalize an
-;;; exhaustive partition or coalesce contiguous ranges of numeric
-;;; types.
-;;;
 ;;; There are all sorts of nasty problems with open bounds on FLOAT
 ;;; types (and probably FLOAT types in general.)
-;;;
-;;; RATIO and BIGNUM are not recognized as numeric types.
 
 ;;; FIXME: This really should go away. Alas, it doesn't seem to be so
 ;;; simple to make it go away.. (See bug 123 in BUGS file.)
       (values
        ;; FIXME: This old CMU CL code probably deserves a comment
        ;; explaining to us mere mortals how it works...
-       (and (sb!xc:typep type2 'sb!xc:class)
+       (and (sb!xc:typep type2 'classoid)
            (dolist (x info nil)
              (when (or (not (cdr x))
                        (csubtypep type1 (specifier-type (cdr x))))
                (return
                 (or (eq type2 (car x))
-                    (let ((inherits (layout-inherits (class-layout (car x)))))
+                    (let ((inherits (layout-inherits
+                                     (classoid-layout (car x)))))
                       (dotimes (i (length inherits) nil)
-                        (when (eq type2 (layout-class (svref inherits i)))
+                        (when (eq type2 (layout-classoid (svref inherits i)))
                           (return t)))))))))
        t)))
 
                              (destructuring-bind
                                  (super &optional guard)
                                  spec
-                               (cons (sb!xc:find-class super) guard)))
+                               (cons (find-classoid super) guard)))
                            ',specs)))
         (setf (type-class-complex-subtypep-arg1 ,type-class)
               (lambda (type1 type2)
                     (csubtypep a1 a2)
                   (unless res (return (values res sure-p))))
              finally (return (values t t)))))
-   (macrolet ((3and (x y)
-                `(multiple-value-bind (val1 win1) ,x
-                   (if (and (not val1) win1)
-                       (values nil t)
-                       (multiple-value-bind (val2 win2) ,y
-                         (if (and val1 val2)
-                             (values t t)
-                             (values nil (and win2 (not val2)))))))))
-     (3and (values-subtypep (fun-type-returns type1)
-                            (fun-type-returns type2))
-           (cond ((fun-type-wild-args type2) (values t t))
-                 ((fun-type-wild-args type1)
-                  (cond ((fun-type-keyp type2) (values nil nil))
-                        ((not (fun-type-rest type2)) (values nil t))
-                        ((not (null (fun-type-required type2))) (values nil t))
-                        (t (3and (type= *universal-type* (fun-type-rest type2))
-                                 (every/type #'type= *universal-type*
-                                             (fun-type-optional type2))))))
-                 ((not (and (fun-type-simple-p type1)
-                            (fun-type-simple-p type2)))
-                  (values nil nil))
-                 (t (multiple-value-bind (min1 max1) (fun-type-nargs type1)
-                      (multiple-value-bind (min2 max2) (fun-type-nargs type2)
-                        (cond ((or (> max1 max2) (< min1 min2))
-                               (values nil t))
-                              ((and (= min1 min2) (= max1 max2))
-                               (3and (every-csubtypep (fun-type-required type1)
-                                                      (fun-type-required type2))
-                                     (every-csubtypep (fun-type-optional type1)
-                                                      (fun-type-optional type2))))
-                              (t (every-csubtypep
-                                  (concatenate 'list
-                                               (fun-type-required type1)
-                                               (fun-type-optional type1))
-                                  (concatenate 'list
-                                               (fun-type-required type2)
-                                               (fun-type-optional type2)))))))))))))
+   (and/type (values-subtypep (fun-type-returns type1)
+                              (fun-type-returns type2))
+             (cond ((fun-type-wild-args type2) (values t t))
+                   ((fun-type-wild-args type1)
+                    (cond ((fun-type-keyp type2) (values nil nil))
+                          ((not (fun-type-rest type2)) (values nil t))
+                          ((not (null (fun-type-required type2))) (values nil t))
+                          (t (and/type (type= *universal-type* (fun-type-rest type2))
+                                       (every/type #'type= *universal-type*
+                                                   (fun-type-optional type2))))))
+                   ((not (and (fun-type-simple-p type1)
+                              (fun-type-simple-p type2)))
+                    (values nil nil))
+                   (t (multiple-value-bind (min1 max1) (fun-type-nargs type1)
+                        (multiple-value-bind (min2 max2) (fun-type-nargs type2)
+                          (cond ((or (> max1 max2) (< min1 min2))
+                                 (values nil t))
+                                ((and (= min1 min2) (= max1 max2))
+                                 (and/type (every-csubtypep (fun-type-required type1)
+                                                            (fun-type-required type2))
+                                           (every-csubtypep (fun-type-optional type1)
+                                                            (fun-type-optional type2))))
+                                (t (every-csubtypep
+                                    (concatenate 'list
+                                                 (fun-type-required type1)
+                                                 (fun-type-optional type1))
+                                    (concatenate 'list
+                                                 (fun-type-required type2)
+                                                 (fun-type-optional type2))))))))))))
 
 (!define-superclasses function ((function)) !cold-init-forms)
 
 ;;; shared logic for unions and intersections: Make a COMPOUND-TYPE
 ;;; object whose components are the types in TYPES, or skip to special
 ;;; cases when TYPES is short.
-(defun make-compound-type-or-something (constructor types enumerable identity)
+(defun make-probably-compound-type (constructor types enumerable identity)
   (declare (type function constructor))
   (declare (type (vector ctype) types))
   (declare (type ctype identity))
                ;; brain-dead, so that would generate a full call to
                ;; SPECIFIER-TYPE at runtime, so we get into bootstrap
                ;; problems in cold init because 'LIST is a compound
-               ;; type, so we need to MAKE-COMPOUND-TYPE-OR-SOMETHING
+               ;; type, so we need to MAKE-PROBABLY-COMPOUND-TYPE
                ;; before we know what 'LIST is. Once the COERCE
                ;; optimizer is less brain-dead, we can make this
                ;; (COERCE TYPES 'LIST) again.
               :specifier `(and ,@(map 'list
                                       #'type-specifier
                                       simplified-types)))))
-       (make-compound-type-or-something #'%make-intersection-type
-                                        simplified-types
-                                        (some #'type-enumerable
-                                              simplified-types)
-                                        *universal-type*))))
+       (make-probably-compound-type #'%make-intersection-type
+                                    simplified-types
+                                    (some #'type-enumerable
+                                          simplified-types)
+                                    *universal-type*))))
 
 (defun type-union (&rest input-types)
   (%type-union input-types))
   (let ((simplified-types (simplified-compound-types input-types
                                                     #'union-type-p
                                                     #'type-union2)))
-    (make-compound-type-or-something #'make-union-type
-                                    simplified-types
-                                    (every #'type-enumerable simplified-types)
-                                    *empty-type*)))
+    (make-probably-compound-type #'make-union-type
+                                simplified-types
+                                (every #'type-enumerable simplified-types)
+                                *empty-type*)))
 \f
 ;;;; built-in types
 
   ;;(aver (not (eq type1 *wild-type*))) ; * isn't really a type.
   (values (eq type1 type2) t))
 
+(!define-type-method (named :complex-=) (type1 type2)
+  (cond
+    ((and (eq type2 *empty-type*)
+         (intersection-type-p type1)
+         ;; not allowed to be unsure on these... FIXME: keep the list
+         ;; of CL types that are intersection types once and only
+         ;; once.
+         (not (or (type= type1 (specifier-type 'ratio))
+                  (type= type1 (specifier-type 'keyword)))))
+     ;; things like (AND (EQL 0) (SATISFIES ODDP)) or (AND FUNCTION
+     ;; STREAM) can get here.  In general, we can't really tell
+     ;; whether these are equal to NIL or not, so
+     (values nil nil))
+    ((type-might-contain-other-types-p type1)
+     (invoke-complex-=-other-method type1 type2))
+    (t (values nil t))))
+
 (!define-type-method (named :simple-subtypep) (type1 type2)
   (aver (not (eq type1 *wild-type*))) ; * isn't really a type.
   (values (or (eq type1 *empty-type*) (eq type2 *wild-type*)) t))
   (aver (not (eq type2 *wild-type*))) ; * isn't really a type.
   (cond ((eq type2 *universal-type*)
         (values t t))
-       ((hairy-type-p type1)
+       ((type-might-contain-other-types-p type1)
+        ;; those types can be *EMPTY-TYPE* or *UNIVERSAL-TYPE* in
+        ;; disguise.  So we'd better delegate.
         (invoke-complex-subtypep-arg1-method type1 type2))
        (t
         ;; FIXME: This seems to rely on there only being 2 or 3
         (intersection2 (type-intersection2 type1
                                            complement-type2)))
     (if intersection2
-       (values (eq intersection2 *empty-type*) t)
+       ;; FIXME: if uncertain, maybe try arg1?
+       (type= intersection2 *empty-type*)
        (invoke-complex-subtypep-arg1-method type1 type2))))
 
 (!define-type-method (negation :complex-subtypep-arg1) (type1 type2)
              (mapcar #'(lambda (x)
                          (specifier-type `(not ,(type-specifier x))))
                      (union-type-types not-type))))
+      ((member-type-p not-type)
+       (let ((members (member-type-members not-type)))
+        (if (some #'floatp members)
+            (let (floats)
+              (dolist (pair '((0.0f0 . -0.0f0) (0.0d0 . -0.0d0)
+                              #!+long-float (0.0l0 . -0.0l0)))
+                (when (member (car pair) members)
+                  (aver (not (member (cdr pair) members)))
+                  (push (cdr pair) floats)
+                  (setf members (remove (car pair) members)))
+                (when (member (cdr pair) members)
+                  (aver (not (member (car pair) members)))
+                  (push (car pair) floats)
+                  (setf members (remove (cdr pair) members))))
+              (apply #'type-intersection
+                     (if (null members)
+                         *universal-type*
+                         (make-negation-type
+                          :type (make-member-type :members members)))
+                     (mapcar
+                      (lambda (x)
+                        (let ((type (ctype-of x)))
+                          (type-union
+                           (make-negation-type
+                            :type (modified-numeric-type type
+                                                         :low nil :high nil))
+                           (modified-numeric-type type
+                                                  :low nil :high (list x))
+                           (make-member-type :members (list x))
+                           (modified-numeric-type type
+                                                  :low (list x) :high nil))))
+                      floats)))
+            (make-negation-type :type not-type))))
       ((and (cons-type-p not-type)
            (eq (cons-type-car-type not-type) *universal-type*)
            (eq (cons-type-cdr-type not-type) *universal-type*))
       (let (ms numbers)
        (dolist (m (remove-duplicates members))
          (typecase m
+           #!-negative-zero-is-not-zero
+           (float (if (zerop m)
+                      (push m ms)
+                      (push (ctype-of m) numbers)))
            (number (push (ctype-of m) numbers))
            (t (push m ms))))
        (apply #'type-union
 ;;; shared machinery for type equality: true if every type in the set
 ;;; TYPES1 matches a type in the set TYPES2 and vice versa
 (defun type=-set (types1 types2)
-  (flet (;; true if every type in the set X matches a type in the set Y
-        (type<=-set (x y)
+  (flet ((type<=-set (x y)
           (declare (type list x y))
-          (every (lambda (xelement)
-                   (position xelement y :test #'type=))
-                 x)))
-    (values (and (type<=-set types1 types2)
-                (type<=-set types2 types1))
-           t)))
+          (every/type (lambda (x y-element)
+                         (any/type #'type= y-element x))
+                       x y)))
+    (and/type (type<=-set types1 types2)
+              (type<=-set types2 types1))))
 
 ;;; Two intersection types are equal if their subtypes are equal sets.
 ;;;
             (intersection-type-types type2)))
 
 (defun %intersection-complex-subtypep-arg1 (type1 type2)
-  (any/type (swapped-args-fun #'csubtypep)
-           type2
-           (intersection-type-types type1)))
+  (type= type1 (type-intersection type1 type2)))
 
 (defun %intersection-simple-subtypep (type1 type2)
   (every/type #'%intersection-complex-subtypep-arg1
        ((and (not (intersection-type-p type1))
              (%intersection-complex-subtypep-arg1 type2 type1))
         type1)
+       ;; KLUDGE: This special (and somewhat hairy) magic is required
+       ;; to deal with the RATIONAL/INTEGER special case.  The UNION
+       ;; of (INTEGER * -1) and (AND (RATIONAL * -1/2) (NOT INTEGER))
+       ;; should be (RATIONAL * -1/2) -- CSR, 2003-02-28
+       ((and (csubtypep type2 (specifier-type 'ratio))
+             (numeric-type-p type1)
+             (csubtypep type1 (specifier-type 'integer))
+             (csubtypep type2
+                        (make-numeric-type
+                         :class 'rational
+                         :complexp nil
+                         :low (if (null (numeric-type-low type1))
+                                  nil
+                                  (list (1- (numeric-type-low type1))))
+                         :high (if (null (numeric-type-high type1))
+                                   nil
+                                   (list (1+ (numeric-type-high type1)))))))
+        (type-union type1
+                    (apply #'type-intersection
+                           (remove (specifier-type '(not integer))
+                                   (intersection-type-types type2)
+                                   :test #'type=))))
        (t
         (let ((accumulator *universal-type*))
           (do ((t2s (intersection-type-types type2) (cdr t2s)))
 
 (!define-type-method (union :complex-=) (type1 type2)
   (declare (ignore type1))
-  (if (some #'(lambda (x) (or (hairy-type-p x)
-                             (negation-type-p x)))
+  (if (some #'type-might-contain-other-types-p 
            (union-type-types type2))
       (values nil nil)
       (values nil t)))
 (defun defined-ftype-matches-declared-ftype-p (defined-ftype declared-ftype)
   (declare (type ctype defined-ftype declared-ftype))
   (flet ((is-built-in-class-function-p (ctype)
-          (and (built-in-class-p ctype)
-               (eq (built-in-class-%name ctype) 'function))))
+          (and (built-in-classoid-p ctype)
+               (eq (built-in-classoid-name ctype) 'function))))
     (cond (;; DECLARED-FTYPE could certainly be #<BUILT-IN-CLASS FUNCTION>;
           ;; that's what happens when we (DECLAIM (FTYPE FUNCTION FOO)).
           (is-built-in-class-function-p declared-ftype)