0.6.11.13:
[sbcl.git] / src / code / late-type.lisp
index 3371b95..0b9ae5f 100644 (file)
@@ -16,6 +16,8 @@
 
 (in-package "SB!KERNEL")
 
+(/show0 "late-type.lisp 19")
+
 (!begin-collecting-cold-init-forms)
 
 ;;; ### Remaining incorrectnesses:
     (if subtypep-arg1
        (funcall subtypep-arg1 type1 type2)
        (values nil t))))
-(defun delegate-complex-intersection (type1 type2)
-  (let ((method (type-class-complex-intersection (type-class-info type1))))
-    (if (and method (not (eq method #'delegate-complex-intersection)))
+(defun delegate-complex-intersection2 (type1 type2)
+  (let ((method (type-class-complex-intersection2 (type-class-info type1))))
+    (if (and method (not (eq method #'delegate-complex-intersection2)))
        (funcall method type2 type1)
-       (vanilla-intersection type1 type2))))
+       (hierarchical-intersection2 type1 type2))))
 
 ;;; This is used by !DEFINE-SUPERCLASSES to define the SUBTYPE-ARG1
 ;;; method. INFO is a list of conses
                 (!has-superclasses-complex-subtypep-arg1 type1 type2 ,info)))
         (setf (type-class-complex-subtypep-arg2 ,type-class)
               #'delegate-complex-subtypep-arg2)
-        (setf (type-class-complex-intersection ,type-class)
-              #'delegate-complex-intersection)))))
+        (setf (type-class-complex-intersection2 ,type-class)
+              #'delegate-complex-intersection2)))))
 \f
 ;;;; FUNCTION and VALUES types
 ;;;;
 ;;;; -- Many of the places that can be annotated with real types can
 ;;;;    also be annotated with function or values types.
 
-;;; the description of a keyword argument
+;;; the description of a &KEY argument
 (defstruct (key-info #-sb-xc-host (:pure t)
                     (:copier nil))
-  ;; the keyword
-  (name (required-argument) :type keyword)
+  ;; the key (not necessarily a keyword in ANSI)
+  (name (required-argument) :type symbol)
   ;; the type of the argument value
   (type (required-argument) :type ctype))
 
 (!define-type-method (values :simple-subtypep :complex-subtypep-arg1)
-                   (type1 type2)
+                    (type1 type2)
   (declare (ignore type2))
-  (error "Subtypep is illegal on this type:~%  ~S" (type-specifier type1)))
+  ;; FIXME: should be TYPE-ERROR, here and in next method
+  (error "SUBTYPEP is illegal on this type:~%  ~S" (type-specifier type1)))
 
 (!define-type-method (values :complex-subtypep-arg2)
-                   (type1 type2)
+                    (type1 type2)
   (declare (ignore type1))
-  (error "Subtypep is illegal on this type:~%  ~S" (type-specifier type2)))
+  (error "SUBTYPEP is illegal on this type:~%  ~S" (type-specifier type2)))
 
 (!define-type-method (values :unparse) (type)
   (cons 'values (unparse-args-types type)))
 (!define-type-method (function :simple-union) (type1 type2)
   (declare (ignore type1 type2))
   (specifier-type 'function))
-(!define-type-method (function :simple-intersection) (type1 type2)
+(!define-type-method (function :simple-intersection2) (type1 type2)
   (declare (ignore type1 type2))
-  (values (specifier-type 'function) t))
+  (specifier-type 'function))
 
 ;;; ### Not very real, but good enough for redefining transforms
 ;;; according to type:
              (t
               (make-union-type-or-something (list type1 type2)))))))
 
-;;; Return as restrictive a type as we can discover that is no more
-;;; restrictive than the intersection of TYPE1 and TYPE2. The second
-;;; value is true if the result is exact. At worst, we randomly return
-;;; one of the arguments as the first value (trying not to return a
-;;; hairy type).
-(defun-cached (type-intersection :hash-function type-cache-hash
-                                :hash-bits 8
-                                :values 2
-                                :default (values nil :empty)
-                                :init-wrapper !cold-init-forms)
+;;; the type method dispatch case of TYPE-INTERSECTION2
+(defun %type-intersection2 (type1 type2)
+  ;; We want to give both argument orders a chance at
+  ;; COMPLEX-INTERSECTION2. Without that, the old CMU CL type
+  ;; methods could give noncommutative results, e.g.
+  ;;   (TYPE-INTERSECTION2 *EMPTY-TYPE* SOME-HAIRY-TYPE)
+  ;;     => NIL, NIL
+  ;;   (TYPE-INTERSECTION2 SOME-HAIRY-TYPE *EMPTY-TYPE*)
+  ;;     => #<NAMED-TYPE NIL>, T
+  ;; We also need to distinguish between the case where we found a
+  ;; type method, and it returned NIL, and the case where we fell
+  ;; through without finding any type method. An example of the first
+  ;; case is the intersection of a HAIRY-TYPE with some ordinary type.
+  ;; An example of the second case is the intersection of two
+  ;; completely-unrelated types, e.g. CONS and NUMBER, or SYMBOL and
+  ;; ARRAY.
+  ;;
+  ;; (Why yes, CLOS probably *would* be nicer..)
+  (flet ((1way (x y)
+          (!invoke-type-method :simple-intersection2 :complex-intersection2
+                               x y
+                               :default :no-type-method-found)))
+    (declare (inline 1way))
+    (let ((xy (1way type1 type2)))
+      (or (and (not (eql xy :no-type-method-found)) xy)
+         (let ((yx (1way type2 type1)))
+           (or (and (not (eql yx :no-type-method-found)) yx)
+               (cond ((and (eql xy :no-type-method-found)
+                           (eql yx :no-type-method-found))
+                      *empty-type*)
+                     (t
+                      (assert (and (not xy) (not yx))) ; else handled above
+                      nil))))))))
+
+(defun-cached (type-intersection2 :hash-function type-cache-hash
+                                 :hash-bits 8
+                                 :values 1
+                                 :default nil
+                                 :init-wrapper !cold-init-forms)
              ((type1 eq) (type2 eq))
   (declare (type ctype type1 type2))
-  (if (eq type1 type2)
-      (values type1 t)
-      (!invoke-type-method :simple-intersection :complex-intersection
-                          type1 type2
-                          :default (values *empty-type* t))))
+  (cond ((eq type1 type2)
+        type1)
+       ((or (intersection-type-p type1)
+            (intersection-type-p type2))
+        ;; Intersections of INTERSECTION-TYPE should have the
+        ;; INTERSECTION-TYPE-TYPES objects broken out and intersected
+        ;; separately. The full TYPE-INTERSECTION function knows how
+        ;; to do that, so let it handle it.
+        (type-intersection type1 type2))
+       (t
+        ;; the ordinary case: we dispatch to type methods
+        (%type-intersection2 type1 type2))))
+
+;;; Return as restrictive and simple a type as we can discover that is
+;;; no more restrictive than the intersection of TYPE1 and TYPE2. At
+;;; worst, we arbitrarily return one of the arguments as the first
+;;; value (trying not to return a hairy type).
+(defun type-approx-intersection2 (type1 type2)
+  (cond ((type-intersection2 type1 type2))
+       ((hairy-type-p type1) type2)
+       (t type1)))
 
 ;;; The first value is true unless the types don't intersect. The
 ;;; second value is true if the first value is definitely correct. NIL
 ;;; is considered to intersect with any type. If T is a subtype of
-;;; either type, then we also return T, T. This way we consider hairy
-;;; types to intersect with T.
+;;; either type, then we also return T, T. This way we recognize
+;;; that hairy types might intersect with T.
+;;;
+;;; FIXME: It would be more accurate to call this TYPES-MIGHT-INTERSECT,
+;;; and rename VALUES-TYPES-INTERSECT the same way.
 (defun types-intersect (type1 type2)
   (declare (type ctype type1 type2))
   (if (or (eq type1 *empty-type*) (eq type2 *empty-type*))
       (values t t)
-      (multiple-value-bind (val winp) (type-intersection type1 type2)
-       (cond ((not winp)
+      (let ((intersection2 (type-intersection2 type1 type2)))
+       (cond ((not intersection2)
               (if (or (csubtypep *universal-type* type1)
                       (csubtypep *universal-type* type2))
                   (values t t)
                   (values t nil)))
-             ((eq val *empty-type*) (values nil t))
+             ((eq intersection2 *empty-type*) (values nil t))
              (t (values t t))))))
 
 ;;; Return a Common Lisp type specifier corresponding to the TYPE
        (setf (info :type :kind spec) :primitive))))
   (values))
 \f
+;;;; general TYPE-UNION and TYPE-INTERSECTION operations
+;;;;
+;;;; These are fully general operations on CTYPEs: they'll always
+;;;; return a CTYPE representing the result.
+
+;;; shared logic for unions and intersections: Stuff TYPE into the
+;;; vector TYPES, finding pairs of types which can be simplified by
+;;; SIMPLIFY2 and replacing them by their simplified forms.
+(defun accumulate-compound-type (type types simplify2)
+  (declare (type ctype type))
+  (declare (type (vector t) types))
+  (declare (type function simplify2))
+  (dotimes (i (length types) (vector-push-extend type types))
+    (let ((simplified2 (funcall simplify2 type (aref types i))))
+      (when simplified2
+       ;; Discard the old (AREF TYPES I).
+       (setf (aref types i) (vector-pop types))
+       ;; Add the new SIMPLIFIED2 to TYPES, by tail recursing.
+       (return (accumulate-compound-type simplified2
+                                         types
+                                         simplify2)))))
+  (values))
+
+;;; 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-VECTOR is short.
+(defun make-compound-type-or-something (constructor types enumerable identity)
+  (declare (type function constructor))
+  (declare (type (vector t) types))
+  (declare (type ctype identity))
+  (case (length types)
+    (0 identity)
+    (1 (the ctype (aref types 0)))
+    (t (funcall constructor enumerable (coerce types 'list)))))
+
+(defun type-intersection (&rest input-types)
+  (let (;; components of our result, accumulated as a vector
+       (simplified-types (make-array (length input-types) :fill-pointer 0)))
+    (flet ((accumulate (type)
+            (accumulate-compound-type type
+                                      simplified-types
+                                      #'type-intersection2)))
+      (declare (inline accumulate))
+      (dolist (type input-types)
+       (if (intersection-type-p type)
+           (map nil #'accumulate (intersection-type-types type))
+           (accumulate type)))
+      ;; We want to have a canonical representation of types (or failing
+      ;; that, punt to HAIRY-TYPE). Canonical representation would have
+      ;; intersections inside unions but not vice versa, since you can
+      ;; always achieve that by the distributive rule. But we don't want
+      ;; to just apply the distributive rule, since it would be too easy
+      ;; to end up with unreasonably huge type expressions. So instead
+      ;; we punt to HAIRY-TYPE when this comes up.
+      (if (and (> (length simplified-types) 1)
+              (some #'union-type-p simplified-types))
+         (make-hairy-type
+          :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*)))))
+
+;;; FIXME: Define TYPE-UNION similar to TYPE-INTERSECTION.
+\f
 ;;;; built-in types
 
 (!define-type-class named)
    (frob t *universal-type*)))
 
 (!define-type-method (named :simple-=) (type1 type2)
+  ;; FIXME: BUG 85: This assertion failed when I added it in
+  ;; sbcl-0.6.11.13. It probably shouldn't fail; but for now it's
+  ;; just commented out.
+  ;;(assert (not (eq type1 *wild-type*))) ; * isn't really a type.
   (values (eq type1 type2) t))
 
 (!define-type-method (named :simple-subtypep) (type1 type2)
+  (assert (not (eq type1 *wild-type*))) ; * isn't really a type.
   (values (or (eq type1 *empty-type*) (eq type2 *wild-type*)) t))
 
 (!define-type-method (named :complex-subtypep-arg1) (type1 type2)
-  (assert (not (hairy-type-p type2)))
+  (assert (not (eq type1 *wild-type*))) ; * isn't really a type.
+  ;; FIXME: Why does this (old CMU CL) assertion hold? Perhaps 'cause
+  ;; the HAIRY-TYPE COMPLEX-SUBTYPEP-ARG2 method takes precedence over
+  ;; this COMPLEX-SUBTYPE-ARG1 method? (I miss CLOS..)
+  (assert (not (hairy-type-p type2))) 
+  ;; Besides the old CMU CL assertion above, we also need to avoid
+  ;; compound types, else we could get into trouble with
+  ;;   (SUBTYPEP 'T '(OR (SATISFIES FOO) (SATISFIES BAR)))
+  ;; or
+  ;;   (SUBTYPEP 'T '(AND (SATISFIES FOO) (SATISFIES BAR))).
+  (assert (not (compound-type-p type2))) 
+  ;; Then, since TYPE2 is reasonably tractable, we're good to go.
   (values (eq type1 *empty-type*) t))
 
 (!define-type-method (named :complex-subtypep-arg2) (type1 type2)
-  (if (hairy-type-p type1)
-      (values nil nil)
-      (values (not (eq type2 *empty-type*)) t)))
-
-(!define-type-method (named :complex-intersection) (type1 type2)
-  (vanilla-intersection type1 type2))
+  (assert (not (eq type2 *wild-type*))) ; * isn't really a type.
+  (cond ((eq type2 *universal-type*)
+        (values t t))
+       ((hairy-type-p type1)
+        (values nil nil))
+       (t
+        ;; FIXME: This seems to rely on there only being 2 or 3
+        ;; HAIRY-TYPE values, and the exclusion of various
+        ;; possibilities above. It would be good to explain it and/or
+        ;; rewrite it so that it's clearer.
+        (values (not (eq type2 *empty-type*)) t))))
+
+(!define-type-method (named :complex-intersection2) (type1 type2)
+  ;; FIXME: This assertion failed when I added it in sbcl-0.6.11.13.
+  ;; Perhaps when bug 85 is fixed it can be reenabled.
+  ;;(assert (not (eq type2 *wild-type*))) ; * isn't really a type.
+  (hierarchical-intersection2 type1 type2))
 
 (!define-type-method (named :unparse) (x)
   (named-type-name x))
 (!define-type-method (hairy :complex-subtypep-arg2) (type1 type2)
   (let ((hairy-spec (hairy-type-specifier type2)))
     (cond ((and (consp hairy-spec) (eq (car hairy-spec) 'not))
-          (multiple-value-bind (val win)
-              (type-intersection type1 (specifier-type (cadr hairy-spec)))
-            (if win
-                (values (eq val *empty-type*) t)
+          (let* ((complement-type2 (specifier-type (cadr hairy-spec)))
+                 (intersection2 (type-intersection2 type1
+                                                    complement-type2)))
+            (if intersection2
+                (values (eq intersection2 *empty-type*) t)
                 (values nil nil))))
          (t
           (values nil nil)))))
   (declare (ignore type1 type2))
   (values nil nil))
 
-(!define-type-method (hairy :simple-intersection :complex-intersection)
-                   (type1 type2)
-  (declare (ignore type2))
-  (values type1 nil))
+(!define-type-method (hairy :simple-intersection2 :complex-intersection2)
+                    (type1 type2)
+  (declare (ignore type1 type2))
+  nil)
 
 (!define-type-method (hairy :complex-union) (type1 type2)
   (make-union-type-or-something (list type1 type2)))
 \f
 ;;;; numeric types
 
-;;; A list of all the float formats, in order of decreasing precision.
-(eval-when (:compile-toplevel :load-toplevel :execute)
-  (defparameter *float-formats*
-    '(long-float double-float single-float short-float)))
-
-;;; The type of a float format.
-(deftype float-format () `(member ,@*float-formats*))
-
 #!+negative-zero-is-not-zero
 (defun make-numeric-type (&key class format (complexp :real) low high
                               enumerable)
                       :low lb
                       :high hb)))
 
-(defmacro def-bounded-type (type class format)
+(defmacro !def-bounded-type (type class format)
   `(!def-type-translator ,type (&optional (low '*) (high '*))
      (let ((lb (canonicalized-bound low ',type))
           (hb (canonicalized-bound high ',type)))
         (error "Lower bound ~S is not less than upper bound ~S." low high))
        (make-numeric-type :class ',class :format ',format :low lb :high hb))))
 
-(def-bounded-type rational rational nil)
-(def-bounded-type float float nil)
-(def-bounded-type real nil nil)
+(!def-bounded-type rational rational nil)
+(!def-bounded-type float float nil)
+(!def-bounded-type real nil nil)
 
-(defmacro define-float-format (f)
-  `(def-bounded-type ,f float ,f))
+(defmacro !define-float-format (f)
+  `(!def-bounded-type ,f float ,f))
 
-(define-float-format short-float)
-(define-float-format single-float)
-(define-float-format double-float)
-(define-float-format long-float)
+(!define-float-format short-float)
+(!define-float-format single-float)
+(!define-float-format double-float)
+(!define-float-format long-float)
 
 (defun numeric-types-intersect (type1 type2)
   (declare (type numeric-type type1 type2))
             (if (consp x) (list res) res)))))
       nil))
 
-;;; Handle the case of TYPE-INTERSECTION on two numeric types. We use
+;;; Handle the case of type intersection on two numeric types. We use
 ;;; TYPES-INTERSECT to throw out the case of types with no
 ;;; intersection. If an attribute in TYPE1 is unspecified, then we use
 ;;; TYPE2's attribute, which must be at least as restrictive. If the
 ;;; appropriate numeric type before maximizing. This avoids possible
 ;;; confusion due to mixed-type comparisons (but I think the result is
 ;;; the same).
-(!define-type-method (number :simple-intersection) (type1 type2)
+(!define-type-method (number :simple-intersection2) (type1 type2)
   (declare (type numeric-type type1 type2))
   (if (numeric-types-intersect type1 type2)
       (let* ((class1 (numeric-type-class type1))
                                       'rational))))
             (format (or (numeric-type-format type1)
                         (numeric-type-format type2))))
-       (values
-        (make-numeric-type
-         :class class
-         :format format
-         :complexp (or (numeric-type-complexp type1)
-                       (numeric-type-complexp type2))
-         :low (numeric-bound-max
-               (round-numeric-bound (numeric-type-low type1)
-                                    class format t)
-               (round-numeric-bound (numeric-type-low type2)
-                                    class format t)
-               > >= nil)
-         :high (numeric-bound-max
-                (round-numeric-bound (numeric-type-high type1)
-                                     class format nil)
-                (round-numeric-bound (numeric-type-high type2)
-                                     class format nil)
-                < <= nil))
-        t))
-      (values *empty-type* t)))
+       (make-numeric-type
+        :class class
+        :format format
+        :complexp (or (numeric-type-complexp type1)
+                      (numeric-type-complexp type2))
+        :low (numeric-bound-max
+              (round-numeric-bound (numeric-type-low type1)
+                                   class format t)
+              (round-numeric-bound (numeric-type-low type2)
+                                   class format t)
+              > >= nil)
+        :high (numeric-bound-max
+               (round-numeric-bound (numeric-type-high type1)
+                                    class format nil)
+               (round-numeric-bound (numeric-type-high type2)
+                                    class format nil)
+               < <= nil)))
+      *empty-type*))
 
 ;;; Given two float formats, return the one with more precision. If
 ;;; either one is null, return NIL.
          (t
           (values nil t)))))
 
-(!define-type-method (array :simple-intersection) (type1 type2)
+(!define-type-method (array :simple-intersection2) (type1 type2)
   (declare (type array-type type1 type2))
   (if (array-types-intersect type1 type2)
       (let ((dims1 (array-type-dimensions type1))
            (complexp2 (array-type-complexp type2))
            (eltype1 (array-type-element-type type1))
            (eltype2 (array-type-element-type type2)))
-       (values
-        (specialize-array-type
-         (make-array-type
-          :dimensions (cond ((eq dims1 '*) dims2)
-                            ((eq dims2 '*) dims1)
-                            (t
-                             (mapcar (lambda (x y) (if (eq x '*) y x))
-                                     dims1 dims2)))
-          :complexp (if (eq complexp1 :maybe) complexp2 complexp1)
-          :element-type (if (eq eltype1 *wild-type*) eltype2 eltype1)))
-        t))
-      (values *empty-type* t)))
+       (specialize-array-type
+        (make-array-type
+         :dimensions (cond ((eq dims1 '*) dims2)
+                           ((eq dims2 '*) dims1)
+                           (t
+                            (mapcar (lambda (x y) (if (eq x '*) y x))
+                                    dims1 dims2)))
+         :complexp (if (eq complexp1 :maybe) complexp2 complexp1)
+         :element-type (if (eq eltype1 *wild-type*) eltype2 eltype1))))
+      *empty-type*))
 
 ;;; Check a supplied dimension list to determine whether it is legal,
 ;;; and return it in canonical form (as either '* or a list).
 (!define-type-method (member :complex-subtypep-arg2) (type1 type2)
   (cond ((not (type-enumerable type1)) (values nil t))
        ((types-intersect type1 type2) (values nil nil))
-       (t
-        (values nil t))))
+       (t (values nil t))))
 
-(!define-type-method (member :simple-intersection) (type1 type2)
+(!define-type-method (member :simple-intersection2) (type1 type2)
   (let ((mem1 (member-type-members type1))
        (mem2 (member-type-members type2)))
-    (values (cond ((subsetp mem1 mem2) type1)
-                 ((subsetp mem2 mem1) type2)
-                 (t
-                  (let ((res (intersection mem1 mem2)))
-                    (if res
-                        (make-member-type :members res)
-                        *empty-type*))))
-           t)))
+    (cond ((subsetp mem1 mem2) type1)
+         ((subsetp mem2 mem1) type2)
+         (t
+          (let ((res (intersection mem1 mem2)))
+            (if res
+                (make-member-type :members res)
+                *empty-type*))))))
 
-(!define-type-method (member :complex-intersection) (type1 type2)
+(!define-type-method (member :complex-intersection2) (type1 type2)
   (block punt               
     (collect ((members))
       (let ((mem2 (member-type-members type2)))
         (dolist (member mem2)
          (multiple-value-bind (val win) (ctypep member type1)
            (unless win
-             (return-from punt (values type2 nil)))
+             (return-from punt nil))
            (when val (members member))))
-
-       (values (cond ((subsetp mem2 (members)) type2)
-                     ((null (members)) *empty-type*)
-                     (t
-                      (make-member-type :members (members))))
-               t)))))
+       (cond ((subsetp mem2 (members)) type2)
+             ((null (members)) *empty-type*)
+             (t
+              (make-member-type :members (members))))))))
 
 ;;; We don't need a :COMPLEX-UNION, since the only interesting case is
 ;;; a union type, and the member/union interaction is handled by the
 ;;;; (to the opaque HAIRY-TYPE) on sufficiently complicated types
 ;;;; involving AND.
 
-;;; In general, make an INTERSECTION-TYPE object from the specifier
-;;; types. But in various special cases, dodge instead, representing
-;;; the intersection type in some other way.
-(defun make-intersection-type-or-something (types)
-  (declare (list types))
-  (/show0 "entering MAKE-INTERSECTION-TYPE-OR-SOMETHING")
-  (cond ((null types)
-        *universal-type*)
-       ((null (cdr types))
-        (first types))
-       (;; if potentially too hairy
-        (some (lambda (type)
-                ;; Allowing irreducible union types into intersection
-                ;; types leads to issues of canonicalization. Those might
-                ;; be soluble but it would be nicer just to avoid them
-                ;; entirely by punting to HAIRY-TYPE. -- WHN 2001-03-02
-                (union-type-p type))
-              types)
-        ;; (CMU CL punted to HAIRY-TYPE like this for all AND-based
-        ;; types. We don't want to do that for simple intersection
-        ;; types like the definition of KEYWORD, hence the guard
-        ;; clause above. But we do want to punt for any really
-        ;; unreasonable cases which might have motivated them to punt
-        ;; in all cases, hence the punt-to-HAIRY-TYPE code below.)
-        (make-hairy-type :specifier `(and ,@(mapcar #'type-specifier types))))
-       (t
-        (%make-intersection-type (some #'type-enumerable types) types))))
-
 (!define-type-class intersection)
 
 ;;; A few intersection types have special names. The others just get
 ;;; mechanically unparsed.
 (!define-type-method (intersection :unparse) (type)
   (declare (type ctype type))
-  (/show0 "entering INTERSECTION :UNPARSE")
   (or (find type '(ratio bignum keyword) :key #'specifier-type :test #'type=)
       `(and ,@(mapcar #'type-specifier (intersection-type-types type)))))
 
 ;;; 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)
-  (/show0 "entering TYPE=-SET")
   (flet (;; true if every type in the set X matches a type in the set Y
         (type<=-set (x y)
           (declare (type list x y))
 ;;; most about, so it would be good to leverage any ingenuity there
 ;;; in this more obscure method?
 (!define-type-method (intersection :simple-=) (type1 type2)
-  (/show0 "entering INTERSECTION :SIMPLE-=")
   (type=-set (intersection-type-types type1)
             (intersection-type-types type2)))
 
 (!define-type-method (intersection :simple-subtypep) (type1 type2)
-  (/show0 "entering INTERSECTION :SIMPLE-SUBTYPEP")
   (let ((certain? t))
     (dolist (t1 (intersection-type-types type1) (values nil certain?))
       (multiple-value-bind (subtypep validp)
               (return (values t t))))))))
 
 (!define-type-method (intersection :complex-subtypep-arg1) (type1 type2)
-  (/show0 "entering INTERSECTION :COMPLEX-SUBTYPEP-ARG1")
   (any/type (swapped-args-fun #'csubtypep)
            type2
            (intersection-type-types type1)))
 (defun intersection-complex-subtypep-arg2 (type1 type2)
   (every/type #'csubtypep type1 (intersection-type-types type2)))
 (!define-type-method (intersection :complex-subtypep-arg2) (type1 type2)
-  (/show0 "entering INTERSECTION :COMPLEX-SUBTYPEP-ARG2")
   (intersection-complex-subtypep-arg2 type1 type2))
 
-;;; shared logic for unions and intersections: Return a new type list
-;;; where pairs of types which can be simplified by SIMPLIFY2-FUN have
-;;; been replaced by their simplified forms.
-(defun simplify-types (types simplify2-fun)
-  (declare (type function simplify2-fun))
-  (let (;; our result, accumulated as a vector
-       (a (make-array (length types) :fill-pointer 0)))
-    (dolist (%type types (coerce a 'list))
-      ;; Merge TYPE into RESULT.
-      (named-let again ((type %type))
-       (dotimes (i (length a) (vector-push-extend type a))
-         (let ((ai (aref a i)))
-           (multiple-value-bind (simplified win?)
-               (funcall simplify2-fun type ai)
-             (when win?
-               (setf (aref a i) (vector-pop a))
-               ;; Give the new SIMPLIFIED its own chance to be
-               ;; pairwise simplified w.r.t. elements of A.
-               (return (again simplified))))))))))
-
-;;; FIXME: See FIXME note for DEFUN SIMPLIFY2-UNION.
-(defun simplify2-intersection (x y)
-  (let ((intersection (type-intersection x y)))
-    (if (and (or (intersection-type-p intersection)
-                (hairy-type-p intersection))
-            (not (intersection-type-p x))
-            (not (intersection-type-p y)))
-       (values nil nil)
-       (values intersection t))))
-    
-(!define-type-method (intersection :simple-intersection :complex-intersection)
-                    (type1 type2)
-  (/show0 "entering INTERSECTION :SIMPLE-INTERSECTION :COMPLEX-INTERSECTION")
-  (flet ((type-components (type)
-          (typecase type
-            (intersection-type (intersection-type-types type))
-            (t (list type)))))
-    (make-intersection-type-or-something
-     ;; FIXME: Here and in MAKE-UNION-TYPE and perhaps elsewhere we
-     ;; should be looking for simplifications and putting things into
-     ;; canonical form.
-     (append (type-components type1)
-            (type-components type2)))))
-
 (!def-type-translator and (&whole whole &rest type-specifiers)
-
-  (/show0 "entering type translator for AND")
-
-  ;; FIXME: doesn't work (causes cold boot to fail), should probably
-  ;; be replaced by something based on simplification of all possible
-  ;; pairs
-  #|
-  (make-intersection-type-or-something
-   (mapcar #'specifier-type type-specifiers))
-  |#
-
-  ;; substantially the old CMU CL code
-  ;;
-  ;; FIXME: should be replaced by something based on simplification
-  ;; of all pairs, not just adjacent pairs
-  (let ((res *wild-type*))
-    (dolist (type-specifier type-specifiers res)
-      (let ((ctype (specifier-type type-specifier)))
-       (multiple-value-bind (int win) (type-intersection res ctype)
-         (unless win
-           (return (make-hairy-type :specifier whole)))
-         (setq res int))))))
+  (apply #'type-intersection
+        (mapcar #'specifier-type
+                type-specifiers)))
 \f
 ;;;; union types
 
 ;;; recognize a special case which can be represented more simply.
 (defun make-union-type-or-something (types)
   (declare (list types))
-  (/show0 "entering MAKE-UNION-TYPE-OR-SOMETHING")
   (cond ((null types)
         *empty-type*)
        ((null (cdr types))
 
 (!define-type-class union)
 
-;;; The LIST type has a special name. Other union types
-;;; just get mechanically unparsed.
+;;; The LIST type has a special name. Other union types just get
+;;; mechanically unparsed.
 (!define-type-method (union :unparse) (type)
   (declare (type ctype type))
   (if (type= type (specifier-type 'list))
            ((not subtypep)
             (return (values nil t)))))))
 
-(!define-type-method (union :complex-subtypep-arg1) (type1 type2)
+(defun union-complex-subtypep-arg1 (type1 type2)
   (every/type (swapped-args-fun #'csubtypep)
              type2
              (union-type-types type1)))
+(!define-type-method (union :complex-subtypep-arg1) (type1 type2)
+  (union-complex-subtypep-arg1 type1 type2))
 
 (defun union-complex-subtypep-arg2 (type1 type2)
   (any/type #'csubtypep type1 (union-type-types type2)))
     (dolist (t2 (union-type-types type2) res)
       (setq res (type-union res t2)))))
 
-(!define-type-method (union :simple-intersection :complex-intersection)
-                    (type1 type2)
-  (let ((res *empty-type*)
-       (win t))
-    (dolist (type (union-type-types type2) (values res win))
-      (multiple-value-bind (int w) (type-intersection type1 type)
-       (setq res (type-union res int))
-       (unless w (setq win nil))))))
-
-;;; FIXME: Obviously, this could be implemented more efficiently if it
-;;; were a primitive. (Making it construct the entire result before
-;;; discarding it because it turns out to be insufficiently simple is
-;;; less than optimum.) A little less obviously, if it were a
-;;; primitive, we could use it a lot more -- basically everywhere we
-;;; do MAKE-UNION-TYPE-OR-SOMETHING. So perhaps this should become
-;;; a primitive; and SIMPLIFY2-INTERSECTION, too, for the same reason.
-(defun simplify2-union (x y)
-  (let ((union (type-union x y)))
-    (if (and (or (union-type-p union)
-                (hairy-type-p union))
-            (not (union-type-p x))
-            (not (union-type-p y)))
-       (values nil nil)
-       (values union t))))
+(!define-type-method (union :simple-intersection2 :complex-intersection2)
+                    (type1 type2)
+  ;; The CSUBTYPEP clauses here let us simplify e.g.
+  ;;   (TYPE-INTERSECTION2 (SPECIFIER-TYPE 'LIST)
+  ;;                       (SPECIFIER-TYPE '(OR LIST VECTOR)))
+  ;; (where LIST is (OR CONS NULL)).
+  ;;
+  ;; The tests are more or less (CSUBTYPEP TYPE1 TYPE2) and vice
+  ;; versa, but it's important that we pre-expand them into
+  ;; specialized operations on individual elements of
+  ;; UNION-TYPE-TYPES, instead of using the ordinary call to
+  ;; CSUBTYPEP, in order to avoid possibly invoking any methods which
+  ;; might in turn invoke (TYPE-INTERSECTION2 TYPE1 TYPE2) and thus
+  ;; cause infinite recursion.
+  (cond ((union-complex-subtypep-arg2 type1 type2)
+        type1)
+       ((union-complex-subtypep-arg1 type2 type1)
+        type2)
+       (t 
+        (let (;; a component of TYPE2 whose intersection with TYPE1
+              ;; is nonempty
+              (nontriv-t2 nil))
+          (dolist (t2 (union-type-types type2) (or nontriv-t2 *empty-type*))
+            (unless (eq *empty-type* (type-intersection type1 t2))
+              (if nontriv-t2 ; if this is second nonempty intersection
+                  (return nil) ; too many: can't find nice result
+                  (setf nontriv-t2 t2))))))))
 
 (!def-type-translator or (&rest type-specifiers)
-  ;; FIXME: new code -- doesn't work?
-  #|
-  (make-union-type-or-something
-   (simplify-types (mapcar #'specifier-type type-specifiers)
-                  #'simplify2-union))
-  |#
-  ;; old code
   (reduce #'type-union
          (mapcar #'specifier-type type-specifiers)
          :initial-value *empty-type*))
           (make-cons-type (type-union cdr-type1 cdr-type2)
                           cdr-type1)))))
 
-(!define-type-method (cons :simple-intersection) (type1 type2)
+(!define-type-method (cons :simple-intersection2) (type1 type2)
   (declare (type cons-type type1 type2))
-  (multiple-value-bind (int-car win-car)
-      (type-intersection (cons-type-car-type type1)
-                        (cons-type-car-type type2))
-    (multiple-value-bind (int-cdr win-cdr)
-       (type-intersection (cons-type-cdr-type type1)
-                          (cons-type-cdr-type type2))
-      (values (make-cons-type int-car int-cdr)
-             (and win-car win-cdr)))))
+  (let (car-int2
+       cdr-int2)
+    (and (setf car-int2 (type-intersection2 (cons-type-car-type type1)
+                                           (cons-type-car-type type2)))
+        (setf cdr-int2 (type-intersection2 (cons-type-cdr-type type1)
+                                           (cons-type-cdr-type type2)))
+        (make-cons-type car-int2 cdr-int2))))
 \f
 ;;; Return the type that describes all objects that are in X but not
 ;;; in Y. If we can't determine this type, then return NIL.
                    :complexp nil)))
 \f
 (!defun-from-collected-cold-init-forms !late-type-cold-init)
+
+(/show0 "late-type.lisp end of file")