;; true if other &KEY arguments are allowed
(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))
+
+(defun args-types (lambda-list-like-thing)
+ (multiple-value-bind
+ (required optional restp rest keyp keys allowp auxp aux)
+ (parse-lambda-list-like-thing lambda-list-like-thing)
+ (declare (ignore aux))
+ (when auxp
+ (error "&AUX in a FUNCTION or VALUES type: ~S." lambda-list-like-thing))
+ (let ((required (mapcar #'single-value-specifier-type required))
+ (optional (mapcar #'single-value-specifier-type optional))
+ (rest (when restp (single-value-specifier-type rest)))
+ (keywords
+ (collect ((key-info))
+ (dolist (key keys)
+ (unless (proper-list-of-length-p key 2)
+ (error "Keyword type description is not a two-list: ~S." key))
+ (let ((kwd (first key)))
+ (when (find kwd (key-info) :key #'key-info-name)
+ (error "~@<repeated keyword ~S in lambda list: ~2I~_~S~:>"
+ kwd lambda-list-like-thing))
+ (key-info
+ (make-key-info
+ :name kwd
+ :type (single-value-specifier-type (second key))))))
+ (key-info))))
+ (multiple-value-bind (required optional rest)
+ (canonicalize-args-type-args required optional rest)
+ (values required optional rest keyp keywords allowp)))))
+
(defstruct (values-type
(:include args-type
(class-info (type-class-or-lose 'values)))
(:constructor %make-values-type)
(:copier nil)))
-(define-cached-synonym make-values-type)
+
+(defun make-values-type (&rest initargs
+ &key (args nil argsp) &allow-other-keys)
+ (if argsp
+ (if (eq args '*)
+ *wild-type*
+ (multiple-value-bind (required optional rest keyp keywords allowp)
+ (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)))
(!define-type-class values)
;;; (SPECIFIER-TYPE 'FUNCTION) and its subtypes
(defstruct (fun-type (:include args-type
- (class-info (type-class-or-lose 'function))))
+ (class-info (type-class-or-lose 'function)))
+ (:constructor %make-fun-type))
;; true if the arguments are unrestrictive, i.e. *
(wild-args nil :type boolean)
;; type describing the return values. This is a values type
;; when multiple values were specified for the return.
(returns (missing-arg) :type ctype))
+(defun make-fun-type (&rest initargs
+ &key (args nil argsp) returns &allow-other-keys)
+ (if argsp
+ (if (eq args '*)
+ (if (eq returns *wild-type*)
+ (specifier-type 'function)
+ (%make-fun-type :wild-args t :returns returns))
+ (multiple-value-bind (required optional rest keyp keywords allowp)
+ (args-types args)
+ (if (and (null required)
+ (null optional)
+ (eq rest *universal-type*)
+ (not keyp))
+ (if (eq returns *wild-type*)
+ (specifier-type 'function)
+ (%make-fun-type :wild-args t :returns returns))
+ (%make-fun-type :required required
+ :optional optional
+ :rest rest
+ :keyp keyp
+ :keywords keywords
+ :allowp allowp
+ :returns returns))))
+ ;; FIXME: are we really sure that we won't make something that
+ ;; looks like a completely wild function here?
+ (apply #'%make-fun-type initargs)))
;;; The CONSTANT-TYPE structure represents a use of the CONSTANT-ARG
;;; "type specifier", which is only meaningful in function argument
(if (consp high)
(1- (type-bound-number high))
high)))
- #!+negative-zero-is-not-zero
- (float
- ;; Canonicalize a low bound of (-0.0) to 0.0, and a high
- ;; bound of (+0.0) to -0.0.
- (values (if (and (consp low)
- (floatp (car low))
- (zerop (car low))
- (minusp (float-sign (car low))))
- (float 0.0 (car low))
- low)
- (if (and (consp high)
- (floatp (car high))
- (zerop (car high))
- (plusp (float-sign (car high))))
- (float -0.0 (car high))
- high)))
(t
;; no canonicalization necessary
(values low high)))
(class-info (type-class-or-lose 'member))
(enumerable t))
(:copier nil)
+ (:constructor %make-member-type (members))
#-sb-xc-host (:pure nil))
;; the things in the set, with no duplications
(members nil :type list))
+(defun make-member-type (&key members)
+ (declare (type list members))
+ ;; make sure that we've removed duplicates
+ (aver (= (length members) (length (remove-duplicates 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 ((singlep (subsetp '(-0.0f0 0.0f0) members))
+ (doublep (subsetp '(-0.0d0 0.0d0) members))
+ #!+long-float
+ (longp (subsetp '(-0.0l0 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))))
+ (when doublep
+ (push (ctype-of 0.0d0) union-types)
+ (setf members (set-difference members '(-0.0d0 0.0d0))))
+ #!+long-float
+ (when longp
+ (push (ctype-of 0.0l0) union-types)
+ (setf members (set-difference members '(-0.0l0 0.0l0))))
+ (aver (not (null union-types)))
+ (make-union-type t
+ (if (null members)
+ union-types
+ (cons (%make-member-type members)
+ union-types))))
+ (%make-member-type members))))
;;; A COMPOUND-TYPE is a type defined out of a set of types, the
;;; common parent of UNION-TYPE and INTERSECTION-TYPE.
(if (typep spec 'built-in-classoid)
(or (built-in-classoid-translation spec) spec)
spec))
- ;; FIXME: CL:CLASS objects are type specifiers.
(t
(let* (;; FIXME: This automatic promotion of FOO-style
;; specs to (FOO)-style specs violates the ANSI