(!begin-collecting-cold-init-forms)
-;;; Has the type system been properly initialized? (I.e. is it OK to
-;;; use it?)
-(defvar *type-system-initialized* #+sb-xc-host nil) ; (set in cold load)
-\f
;;;; representations of types
;;; A HAIRY-TYPE represents anything too weird to be described
(defstruct (unknown-type (:include hairy-type)
(:copier nil)))
+(defstruct (negation-type (:include ctype
+ (class-info (type-class-or-lose 'negation))
+ ;; FIXME: is this right? It's
+ ;; what they had before, anyway
+ (enumerable t)
+ (might-contain-other-types-p t))
+ (:copier nil)
+ #!+cmu (:pure nil))
+ (type (missing-arg) :type ctype))
+
+(!define-type-class negation)
+
;;; ARGS-TYPE objects are used both to represent VALUES types and
;;; to represent FUNCTION types.
(defstruct (args-type (:include ctype)
;; true if other &KEY arguments are allowed
(allowp nil :type boolean))
+(defun canonicalize-args-type-args (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
+ morep more-context more-count llk-p)
+ (parse-lambda-list-like-thing lambda-list-like-thing)
+ (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))
+ (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 llk-p)))))
+
(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-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))
+
+(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
+ llk-p)
+ (args-types args)
+ (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))))
+ (class-info (type-class-or-lose 'function)))
+ (: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
;; 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)))
+ (when (and (eq class 'rational)
+ (integerp canonical-low)
+ (integerp canonical-high)
+ (= canonical-low canonical-high))
+ (setf class 'integer))
(%make-numeric-type :class class
:format format
:complexp complexp
:enumerable enumerable))
;;; An ARRAY-TYPE is used to represent any array type, including
-;;; things such as SIMPLE-STRING.
+;;; things such as SIMPLE-BASE-STRING.
(defstruct (array-type (:include ctype
(class-info (type-class-or-lose 'array)))
(:constructor %make-array-type)
(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 `(,(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 `(,(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 `(,(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 `(,(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 `(,(load-time-value (make-unportable-float :long-float-negative-zero)) 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.
;;; 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)
;;
;; FIXME: Most or all other type structure slots could also be :READ-ONLY.
(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*
+ (%make-cons-type car-type cdr-type)))
+
+(defun cons-type-length-info (type)
+ (declare (type cons-type type))
+ (do ((min 1 (1+ min))
+ (cdr (cons-type-cdr-type type) (cons-type-cdr-type cdr)))
+ ((not (cons-type-p cdr))
+ (cond
+ ((csubtypep cdr (specifier-type 'null))
+ (values min t))
+ ((csubtypep *universal-type* cdr)
+ (values min nil))
+ ((type/= (type-intersection (specifier-type 'cons) cdr) *empty-type*)
+ (values min nil))
+ ((type/= (type-intersection (specifier-type 'null) cdr) *empty-type*)
+ (values min t))
+ (t (values min :maybe))))
+ ()))
+
\f
;;;; type utilities
(logand (sxhash x) #x3FF))
:hash-bits 10
:init-wrapper !cold-init-forms)
- ((orig equal))
+ ((orig equal-but-no-car-recursion))
(let ((u (uncross orig)))
(or (info :type :builtin u)
(let ((spec (type-expand u)))
((and (not (eq spec u))
(info :type :builtin spec)))
((eq (info :type :kind spec) :instance)
- (sb!xc:find-class spec))
- ((typep spec 'class)
+ (find-classoid spec))
+ ((typep spec 'classoid)
;; There doesn't seem to be any way to translate
;; (TYPEP SPEC 'BUILT-IN-CLASS) into something which can be
;; executed on the host Common Lisp at cross-compilation time.
#+sb-xc-host (error
"stub: (TYPEP SPEC 'BUILT-IN-CLASS) on xc host")
- (if (typep spec 'built-in-class)
- (or (built-in-class-translation spec) spec)
+ (if (typep spec 'built-in-classoid)
+ (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))
- ((or (and (consp spec) (symbolp (car spec)))
- (symbolp spec))
+ ((or (and (consp spec) (symbolp (car spec))
+ (not (info :type :builtin (car spec))))
+ (and (symbolp spec) (not (info :type :builtin spec))))
(when (and *type-system-initialized*
(not (eq (info :type :kind spec)
:forthcoming-defclass-type)))
;;; 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)
+ (if (eq x '*)
+ *universal-type*
+ (specifier-type x)))
+
;;; Similar to MACROEXPAND, but expands DEFTYPEs. We don't bother
;;; returning a second value.
(defun type-expand (form)
(let ((def (cond ((symbolp form)
(info :type :expander form))
((and (consp form) (symbolp (car form)))
- (info :type :expander (car form)))
+ (info :type :expander (car form)))
(t nil))))
(if def
(type-expand (funcall def (if (consp form) form (list form))))
(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)