+(defun make-member-type (&key members)
+ (declare (type list members))
+ ;; if we have a pair of zeros (e.g. 0.0d0 and -0.0d0), then we can
+ ;; 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 ((n-single (load-time-value
+ (make-unportable-float :single-float-negative-zero)))
+ (n-double (load-time-value
+ (make-unportable-float :double-float-negative-zero)))
+ #!+long-float
+ (n-long (load-time-value
+ (make-unportable-float :long-float-negative-zero)))
+ (singles nil)
+ (doubles nil)
+ #!+long-float
+ (longs nil))
+ ;; Just a single traversal, please! MEMBERS2 starts as with MEMBERS,
+ ;; sans any zeroes -- if there are any paired zeroes then the
+ ;; unpaired ones are added back to it.
+ (let (members2)
+ (dolist (elt members)
+ (if (and (numberp elt) (zerop elt))
+ (typecase elt
+ (single-float (push elt singles))
+ (double-float (push elt doubles))
+ #!+long-float
+ (long-float (push elt longs)))
+ (push elt members2)))
+ (let ((singlep (and (member 0.0f0 singles)
+ (member n-single singles)
+ (or (aver (= 2 (length singles))) t)))
+ (doublep (and (member 0.0d0 doubles)
+ (member n-double doubles)
+ (or (aver (= 2 (length doubles))) t)))
+ #!+long-float
+ (longp (and (member 0.0l0 longs)
+ (member n-long longs)
+ (or (aver (= 2 (lenght longs))) t))))
+ (if (or singlep doublep #!+long-float longp)
+ (let (union-types)
+ (if singlep
+ (push (ctype-of 0.0f0) union-types)
+ (setf members2 (nconc singles members2)))
+ (if doublep
+ (push (ctype-of 0.0d0) union-types)
+ (setf members2 (nconc doubles members2)))
+ #!+long-float
+ (if longp
+ (push (ctype-of 0.0l0) union-types)
+ (setf members2 (nconc longs members2)))
+ (aver (not (null union-types)))
+ (make-union-type t
+ (if (null members2)
+ union-types
+ (cons (%make-member-type members2)
+ union-types))))
+ (%make-member-type members))))))