1 ;;;; type-related stuff which exists only in the target SBCL runtime
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!KERNEL")
14 (!begin-collecting-cold-init-forms
)
16 ;;; If TYPE is a type that we can do a compile-time test on, then
17 ;;; return whether the object is of that type as the first value and
18 ;;; second value true. Otherwise return NIL, NIL.
20 ;;; We give up on unknown types and pick off FUNCTION- and COMPOUND-
21 ;;; types. For STRUCTURE- types, we require that the type be defined
22 ;;; in both the current and compiler environments, and that the
23 ;;; INCLUDES be the same.
25 ;;; KLUDGE: This should probably be a type method instead of a big
26 ;;; ETYPECASE. But then the type method system should probably be CLOS
27 ;;; too, and until that happens wedging more stuff into it might be
28 ;;; messy. So I've left it a big ETYPECASE. -- 2001-03-16
29 (defun ctypep (obj type
)
30 (declare (type ctype type
))
39 #!+sb-simd-pack simd-pack-type
)
40 (values (%%typep obj type
) t
))
42 (if (if (csubtypep type
(specifier-type 'function
))
43 (funcallable-instance-p obj
)
45 (if (eq (classoid-layout type
)
46 (info :type
:compiler-layout
(classoid-name type
)))
47 (values (sb!xc
:typep obj type
) t
)
51 (funcall (etypecase type
52 (intersection-type #'every
/type
)
53 (union-type #'any
/type
))
56 (compound-type-types type
)))
58 (values (functionp obj
) t
))
62 (values (alien-typep obj
(alien-type-type-alien-type type
)) t
))
64 (multiple-value-bind (res win
)
65 (ctypep obj
(negation-type-type type
))
70 ;; Now the tricky stuff.
71 (let* ((hairy-spec (hairy-type-specifier type
))
72 (symbol (if (consp hairy-spec
) (car hairy-spec
) hairy-spec
)))
77 (dolist (spec (cdr hairy-spec
) (values t t
))
78 (multiple-value-bind (res win
)
79 (ctypep obj
(specifier-type spec
))
80 (unless win
(return (values nil nil
)))
81 (unless res
(return (values nil t
)))))))
83 (multiple-value-bind (res win
)
84 (ctypep obj
(specifier-type (cadr hairy-spec
)))
89 ;; If the SATISFIES function is not foldable, we cannot answer!
90 (let* ((form `(,(second hairy-spec
) ',obj
)))
91 (multiple-value-bind (ok result
)
92 (sb!c
::constant-function-call-p form nil nil
)
93 (values (not (null result
)) ok
)))))))))
95 ;;;; miscellaneous interfaces
97 ;;; Clear memoization of all type system operations that can be
98 ;;; altered by type definition/redefinition.
100 (defun clear-type-caches ()
101 ;; FIXME: We would like to differentiate between different cache
102 ;; kinds, but at the moment all our caches pretty much are type
104 (drop-all-hash-caches)
107 ;;; This is like TYPE-OF, only we return a CTYPE structure instead of
108 ;;; a type specifier, and we try to return the type most useful for
109 ;;; type checking, rather than trying to come up with the one that the
110 ;;; user might find most informative.
112 ;;; To avoid inadvertent memory retention we avoid using arrays
113 ;;; and functions as keys.
114 ;;; During cross-compilation, the CTYPE-OF function is not memoized.
115 ;;; Constants get their type stored in their LEAF, so it's ok.
117 (defun-cached (ctype-of :hash-bits
7 :hash-function
#'sxhash
119 ;; an unfortunate aspect of using EQ is that several appearances
120 ;; of the = double-float can be in the cache, but it's
121 ;; probably more efficient overall to use object identity.
123 (flet ((try-cache (x)
125 ;; For functions, the input is a type specifier
126 ;; of the form (FUNCTION (...) ...)
127 (cond ((listp x
) (specifier-type x
)) ; NIL can't occur
128 ((symbolp x
) (make-eql-type x
))
129 (t (ctype-of-number x
))))))
132 (if (funcallable-instance-p x
)
134 (let ((type (sb!impl
::%fun-type x
)))
135 (if (typep type
'(cons (eql function
))) ; sanity test
138 (symbol (if x
(try-cache x
) (specifier-type 'null
)))
139 (number (try-cache x
))
140 (array (ctype-of-array x
))
141 (cons (specifier-type 'cons
))
144 (standard-char (specifier-type 'standard-char
))
145 (base-char (specifier-type 'base-char
))
146 ;; If the last case were expressed as EXTENDED-CHAR,
147 ;; we wrongly get "this is not a (VALUES CTYPE): NIL"
148 ;; because the compiler is too naive to see that
149 ;; the last 2 cases partition CHARACTER.
150 (t (specifier-type 'extended-char
))))
153 (let ((tag (%simd-pack-tag x
)))
154 (svref (load-time-value
155 (coerce (cons (specifier-type 'simd-pack
)
156 (mapcar (lambda (x) (specifier-type `(simd-pack ,x
)))
157 *simd-pack-element-types
*))
160 (if (<= 0 tag
#.
(1- (length *simd-pack-element-types
*)))
166 ;; Helper function that implements (CTYPE-OF x) when X is an array.
167 (defun-cached (ctype-of-array
168 :values
(ctype) ; Bind putative output to this when probing.
170 :hash-function
(lambda (a &aux
(hash cookie
))
172 (dotimes (axis rank hash
)
173 (mixf hash
(%array-dimension a axis
)))
174 (mixf hash
(length a
)))))
175 ;; "type-key" is a perfect hash of rank + widetag + simple-p.
176 ;; If it matches, then compare dims, which are read from the output.
177 ;; The hash of the type-key + dims can have collisions.
178 ((array (lambda (array type-key
)
179 (and (eq type-key cookie
)
180 (let ((dims (array-type-dimensions ctype
)))
182 (dotimes (axis rank t
)
183 (unless (eq (pop (truly-the list dims
))
184 (%array-dimension array axis
))
186 (eq (length array
) (car dims
))))))
187 cookie
) ; Store COOKIE as the single key.
188 &aux
(rank (array-rank array
))
189 (simple-p (if (simple-array-p array
) 1 0))
190 (header-p (array-header-p array
)) ; non-simple or rank <> 1 or both
191 (cookie (the fixnum
(logior (ash (logior (ash rank
1) simple-p
)
192 sb
!vm
:n-widetag-bits
)
193 (array-underlying-widetag array
)))))
194 ;; The value computed on cache miss.
195 (let ((etype (specifier-type (array-element-type array
))))
196 (make-array-type (array-dimensions array
)
197 :complexp
(not (simple-array-p array
))
199 :specialized-element-type etype
)))
201 (!defun-from-collected-cold-init-forms
!target-type-cold-init
)
203 ;;;; Some functions for examining the type system
204 ;;;; which are not needed during self-build.
206 (defun typexpand-all (type-specifier &optional env
)
207 "Takes and expands a type specifier recursively like MACROEXPAND-ALL."
208 ;; TYPE-SPECIFIER is of type TYPE-SPECIFIER, but it is preferable to
209 ;; defer to VALUES-SPECIFIER-TYPE for the check.
210 (declare (type lexenv-designator env
) (ignore env
))
211 ;; I first thought this would not be a good implementation because
212 ;; it signals an error on e.g. (CONS 1 2) until I realized that
213 ;; walking and calling TYPEXPAND would also result in errors, and
214 ;; it actually makes sense.
216 ;; There's still a small problem in that
217 ;; (TYPEXPAND-ALL '(CONS * FIXNUM)) => (CONS T FIXNUM)
218 ;; whereas walking+typexpand would result in (CONS * FIXNUM).
220 ;; Similiarly, (TYPEXPAND-ALL '(FUNCTION (&REST T) *)) => FUNCTION.
221 (type-specifier (values-specifier-type type-specifier
)))
223 (defun defined-type-name-p (name &optional env
)
224 "Returns T if NAME is known to name a type specifier, otherwise NIL."
225 (declare (symbol name
))
226 (declare (ignore env
))
227 (and (info :type
:kind name
) t
))
229 (defun valid-type-specifier-p (type-specifier &optional env
)
230 "Returns T if TYPE-SPECIFIER is a valid type specifier, otherwise NIL.
232 There may be different metrics on what constitutes a \"valid type
233 specifier\" depending on context. If this function does not suit your
234 exact need, you may be able to craft a particular solution using a
235 combination of DEFINED-TYPE-NAME-P and the TYPEXPAND functions.
237 The definition of \"valid type specifier\" employed by this function
238 is based on the following mnemonic:
240 \"Would TYPEP accept it as second argument?\"
242 Except that unlike TYPEP, this function fully supports compound
243 FUNCTION type specifiers, and the VALUES type specifier, too.
245 In particular, VALID-TYPE-SPECIFIER-P will return NIL if
246 TYPE-SPECIFIER is not a class, not a symbol that is known to name a
247 type specifier, and not a cons that represents a known compound type
248 specifier in a syntactically and recursively correct way.
252 (valid-type-specifier-p '(cons * *)) => T
253 (valid-type-specifier-p '#:foo) => NIL
254 (valid-type-specifier-p '(cons * #:foo)) => NIL
255 (valid-type-specifier-p '(cons 1 *) => NIL
258 (declare (ignore env
))
259 ;; We don't even care if the spec is parseable -
260 ;; just deem it invalid.
261 (not (null (ignore-errors
262 (type-or-nil-if-unknown type-specifier t
)))))