Style improvements and minor bugfix from sb-fasteval integration.
[sbcl.git] / src / code / cross-type.lisp
blob18bf0a364b967b702fb110c2d4e76d2f54fcc0ea
1 ;;;; cross-compiler-only versions of TYPEP, TYPE-OF, and related functions
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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 ;;; (This was a useful warning when trying to get bootstrapping
15 ;;; to work, but it's mostly irrelevant noise now that the system
16 ;;; works.)
17 (define-condition cross-type-style-warning (style-warning)
18 ((call :initarg :call
19 :reader cross-type-style-warning-call)
20 (message :reader cross-type-style-warning-message
21 #+cmu :initarg #+cmu :message ; (to stop bogus non-STYLE WARNING)
23 (:report (lambda (c s)
24 (format
26 "cross-compilation-time type ambiguity (should be OK) in ~S:~%~A"
27 (cross-type-style-warning-call c)
28 (cross-type-style-warning-message c)))))
30 ;;; This warning is issued when giving up on a type calculation where a
31 ;;; conservative answer is acceptable. Since a conservative answer is
32 ;;; acceptable, the only downside is lost optimization opportunities.
33 (define-condition cross-type-giving-up-conservatively
34 (cross-type-style-warning)
35 ((message :initform "giving up conservatively"
36 #+cmu :reader #+cmu #.(gensym) ; (to stop bogus non-STYLE WARNING)
37 )))
39 ;;; This warning refers to the flexibility in the ANSI spec with
40 ;;; regard to run-time distinctions between floating point types.
41 ;;; (E.g. the cross-compilation host might not even distinguish
42 ;;; between SINGLE-FLOAT and DOUBLE-FLOAT, so a DOUBLE-FLOAT number
43 ;;; would test positive as SINGLE-FLOAT.) If the target SBCL does make
44 ;;; this distinction, then information is lost. It's not too hard to
45 ;;; contrive situations where this would be a problem. In practice we
46 ;;; don't tend to run into them because all widely used Common Lisp
47 ;;; environments do recognize the distinction between SINGLE-FLOAT and
48 ;;; DOUBLE-FLOAT, and we don't really need the other distinctions
49 ;;; (e.g. between SHORT-FLOAT and SINGLE-FLOAT), so we call
50 ;;; WARN-POSSIBLE-CROSS-TYPE-FLOAT-INFO-LOSS to test at runtime
51 ;;; whether we need to worry about this at all, and not warn unless we
52 ;;; do. If we *do* have to worry about this at runtime, my (WHN
53 ;;; 19990808) guess is that the system will break in multiple places,
54 ;;; so this is a real WARNING, not just a STYLE-WARNING.
55 ;;;
56 ;;; KLUDGE: If we ever try to support LONG-FLOAT or SHORT-FLOAT, this
57 ;;; situation will get a lot more complicated.
58 (defun warn-possible-cross-type-float-info-loss (call)
59 (when (or (subtypep 'single-float 'double-float)
60 (subtypep 'double-float 'single-float))
61 (warn "possible floating point information loss in ~S" call)))
63 (defun sb!xc:type-of (object)
64 (let ((raw-result (type-of object)))
65 (cond ((or (subtypep raw-result 'float)
66 (subtypep raw-result 'complex))
67 (warn-possible-cross-type-float-info-loss
68 `(sb!xc:type-of ,object))
69 raw-result)
70 ((subtypep raw-result 'integer)
71 (cond ((<= 0 object 1)
72 'bit)
73 (;; We can't rely on the host's opinion of whether
74 ;; it's a FIXNUM, but instead test against target
75 ;; MOST-fooITIVE-FIXNUM limits.
76 (fixnump object)
77 'fixnum)
79 'integer)))
80 ((subtypep raw-result 'simple-string)
81 `(simple-base-string ,(length object)))
82 ((subtypep raw-result 'string) 'base-string)
83 ((some (lambda (type) (subtypep raw-result type))
84 '(array character list symbol))
85 raw-result)
87 (error "can't handle TYPE-OF ~S in cross-compilation" object)))))
89 ;;; Is SYMBOL in the CL package? Note that we're testing this on the
90 ;;; cross-compilation host, which could do things any old way. In
91 ;;; particular, it might be in the CL package even though
92 ;;; SYMBOL-PACKAGE is not (FIND-PACKAGE :CL). So we test things
93 ;;; another way.
94 (defun in-cl-package-p (symbol)
95 (eql (find-symbol (symbol-name symbol) :cl)
96 symbol))
98 ;; Return T if SYMBOL is a predicate acceptable for use in a SATISFIES type
99 ;; specifier. We assume that anything in CL: is allowed (see explanation at
100 ;; call point), and beyond that, anything we define has to be expressly listed
101 ;; here, for fear of later unexpected confusion.
102 (defun acceptable-cross-typep-pred (symbol)
103 (and (fboundp symbol)
104 (or (in-cl-package-p symbol)
105 ;; KLUDGE: rather than extensible list of predicates that match
106 ;; in behavior between the host and target lisp, hardcode a few.
107 (memq symbol '(sb!vm:static-symbol-p
108 sb!vm::wired-tls-symbol-p)))))
110 ;;; This is like TYPEP, except that it asks whether HOST-OBJECT would
111 ;;; be of TARGET-TYPE when instantiated on the target SBCL. Since this
112 ;;; is hard to determine in some cases, and since in other cases we
113 ;;; just haven't bothered to try, it needs to return two values, just
114 ;;; like SUBTYPEP: the first value for its conservative opinion (never
115 ;;; T unless it's certain) and the second value to tell whether it's
116 ;;; certain.
117 (defun cross-typep (host-object raw-target-type)
118 (let ((target-type (typexpand raw-target-type)))
119 (flet ((warn-and-give-up ()
120 ;; We don't have to keep track of this as long as system
121 ;; performance is acceptable, since giving up
122 ;; conservatively is a safe way out.
123 #+nil
124 (warn 'cross-type-giving-up-conservatively
125 :call `(cross-typep ,host-object ,raw-target-type))
126 (values nil nil))
127 (warn-about-possible-float-info-loss ()
128 (warn-possible-cross-type-float-info-loss
129 `(cross-typep ,host-object ,raw-target-type)))
130 ;; a convenient idiom for making more matches to special cases:
131 ;; Test both forms of target type for membership in LIST.
133 ;; (In order to avoid having to use too much deep knowledge
134 ;; of types, it's sometimes convenient to test RAW-TARGET-TYPE
135 ;; as well as the expanded type, since we can get matches with
136 ;; just EQL. E.g. SIMPLE-STRING can be matched with EQL, while
137 ;; safely matching its expansion,
138 ;; (OR (SIMPLE-ARRAY CHARACTER (*)) (SIMPLE-BASE-STRING *))
139 ;; would require logic clever enough to know that, e.g., OR is
140 ;; commutative.)
141 (target-type-is-in (list)
142 (or (member raw-target-type list)
143 (member target-type list))))
144 (cond (;; Handle various SBCL-specific types which can't exist on
145 ;; the ANSI cross-compilation host. KLUDGE: This code will
146 ;; need to be tweaked by hand if the names of these types
147 ;; ever change, ugh!
148 (if (consp target-type)
149 (member (car target-type)
150 '(alien))
151 (member target-type
152 '(system-area-pointer
153 sb!alien-internals:alien-value)))
154 (values nil t))
155 (;; special case when TARGET-TYPE isn't a type spec, but
156 ;; instead a CLASS object.
157 (typep target-type 'class)
158 (bug "We don't support CROSS-TYPEP of CLASS type specifiers"))
159 ((and (symbolp target-type)
160 (find-classoid target-type nil)
161 (sb!xc:subtypep target-type 'cl:structure-object)
162 (typep host-object '(or symbol number list character)))
163 (values nil t))
164 ((and (symbolp target-type)
165 (find-class target-type nil)
166 (subtypep target-type 'structure!object))
167 (values (typep host-object target-type) t))
168 (;; easy cases of arrays and vectors
169 (target-type-is-in
170 '(array simple-string simple-vector string vector))
171 (values (typep host-object target-type) t))
172 (;; sequence is not guaranteed to be an exhaustive
173 ;; partition, but it includes at least lists and vectors.
174 (target-type-is-in '(sequence))
175 (if (or (vectorp host-object) (listp host-object))
176 (values t t)
177 (if (typep host-object target-type)
178 (warn-and-give-up)
179 (values nil t))))
180 (;; general cases of vectors
181 (and (not (hairy-type-p (values-specifier-type target-type)))
182 (sb!xc:subtypep target-type 'cl:vector))
183 (if (vectorp host-object)
184 (warn-and-give-up) ; general-case vectors being way too hard
185 (values nil t))) ; but "obviously not a vector" being easy
186 (;; general cases of arrays
187 (and (not (hairy-type-p (values-specifier-type target-type)))
188 (sb!xc:subtypep target-type 'cl:array))
189 (if (arrayp host-object)
190 (warn-and-give-up) ; general-case arrays being way too hard
191 (values nil t))) ; but "obviously not an array" being easy
192 ((target-type-is-in '(*))
193 ;; KLUDGE: SBCL has * as an explicit wild type. While
194 ;; this is sort of logical (because (e.g. (ARRAY * 1)) is
195 ;; a valid type) it's not ANSI: looking at the ANSI
196 ;; definitions of complex types like like ARRAY shows
197 ;; that they consider * different from other type names.
198 ;; Someday we should probably get rid of this non-ANSIism
199 ;; in base SBCL, but until we do, we might as well here
200 ;; in the cross compiler. And in order to make sure that
201 ;; we don't continue doing it after we someday patch
202 ;; SBCL's type system so that * is no longer a type, we
203 ;; make this assertion. -- WHN 2001-08-08
204 (aver (typep (values-specifier-type '*) 'named-type))
205 (values t t))
206 (;; Many simple types are guaranteed to correspond exactly
207 ;; between any host ANSI Common Lisp and the target
208 ;; Common Lisp. (Some array types are too, but they
209 ;; were picked off earlier.)
210 (target-type-is-in
211 '(atom bit character complex cons float function integer keyword
212 list nil null number rational real signed-byte symbol t
213 unsigned-byte))
214 (values (typep host-object target-type) t))
215 (;; Floating point types are guaranteed to correspond,
216 ;; too, but less exactly.
217 (target-type-is-in
218 '(single-float double-float))
219 (cond ((floatp host-object)
220 (warn-about-possible-float-info-loss)
221 (values (typep host-object target-type) t))
223 (values nil t))))
224 (;; Complexes suffer the same kind of problems as arrays.
225 ;; Our dumping logic is based on contents, however, so
226 ;; reasoning about them should be safe
227 (and (not (hairy-type-p (values-specifier-type target-type)))
228 (sb!xc:subtypep target-type 'cl:complex))
229 (if (complexp host-object)
230 (let ((re (realpart host-object))
231 (im (imagpart host-object)))
232 (if (or (and (eq target-type 'complex)
233 (typep re 'rational) (typep im 'rational))
234 (and (equal target-type '(cl:complex single-float))
235 (typep re 'single-float) (typep im 'single-float))
236 (and (equal target-type '(cl:complex double-float))
237 (typep re 'double-float) (typep im 'double-float)))
238 (values t t)
239 (progn
240 ;; We won't know how to dump it either.
241 (warn "Host complex too complex: ~S" host-object)
242 (warn-and-give-up))))
243 (values nil t)))
244 ;; Some types require translation between the cross-compilation
245 ;; host Common Lisp and the target SBCL.
246 ((target-type-is-in '(classoid))
247 (values (typep host-object 'classoid) t))
248 ((target-type-is-in '(fixnum))
249 (values (fixnump host-object) t))
250 ((target-type-is-in '(bignum))
251 (values (and (integerp host-object) (not (fixnump host-object)))
253 ;; Some types are too hard to handle in the positive
254 ;; case, but at least we can be confident in a large
255 ;; fraction of the negative cases..
256 ((target-type-is-in
257 '(base-string simple-base-string simple-string))
258 (if (stringp host-object)
259 (warn-and-give-up)
260 (values nil t)))
261 ((target-type-is-in '(character base-char standard-char))
262 (cond ((typep host-object 'standard-char)
263 (values t t))
264 ((not (characterp host-object))
265 (values nil t))
267 (warn-and-give-up))))
268 ((target-type-is-in '(stream instance))
269 ;; Neither target CL:STREAM nor target SB!KERNEL:INSTANCE
270 ;; is implemented as a STRUCTURE-OBJECT, so they'll fall
271 ;; through the tests above. We don't want to assume too
272 ;; much about them here, but at least we know enough
273 ;; about them to say that neither T nor NIL nor indeed
274 ;; any other symbol in the cross-compilation host is one.
275 ;; That knowledge suffices to answer so many of the
276 ;; questions that the cross-compiler asks that it's well
277 ;; worth special-casing it here.
278 (if (symbolp host-object)
279 (values nil t)
280 (warn-and-give-up)))
281 ;; various hacks for composite types..
282 ((consp target-type)
283 (let ((first (first target-type))
284 (rest (rest target-type)))
285 (case first
286 ;; Many complex types are guaranteed to correspond exactly
287 ;; between any host ANSI Common Lisp and the target SBCL.
288 ((integer member mod rational real signed-byte unsigned-byte)
289 (values (typep host-object target-type) t))
290 ;; Floating point types are guaranteed to correspond,
291 ;; too, but less exactly.
292 ((single-float double-float)
293 (cond ((floatp host-object)
294 (warn-about-possible-float-info-loss)
295 (values (typep host-object target-type) t))
297 (values nil t))))
298 ;; Some complex types have translations that are less
299 ;; trivial.
300 (and (every/type #'cross-typep host-object rest))
301 (or (any/type #'cross-typep host-object rest))
302 (not
303 (multiple-value-bind (value surep)
304 (cross-typep host-object (car rest))
305 (if surep
306 (values (not value) t)
307 (warn-and-give-up))))
308 ;; If we want to work with the KEYWORD type, we need
309 ;; to grok (SATISFIES KEYWORDP).
310 (satisfies
311 (destructuring-bind (predicate-name) rest
312 (if (acceptable-cross-typep-pred predicate-name)
313 ;; Many predicates like KEYWORDP, ODDP, PACKAGEP,
314 ;; and NULL correspond between host and target.
315 ;; But we still need to handle errors, because
316 ;; the code which calls us may not understand
317 ;; that a type is unreachable. (E.g. when compiling
318 ;; (AND STRING (SATISFIES ARRAY-HAS-FILL-POINTER-P))
319 ;; CTYPEP may be called on the SATISFIES expression
320 ;; even for non-STRINGs.)
321 (multiple-value-bind (result error?)
322 (ignore-errors (funcall predicate-name
323 host-object))
324 (if error?
325 (values nil nil)
326 (values result t)))
327 ;; For symbols not in the CL package, it's not
328 ;; in general clear how things correspond
329 ;; between host and target, so we punt.
330 (warn-and-give-up))))
331 ;; Some complex types are too hard to handle in the
332 ;; positive case, but at least we can be confident in
333 ;; a large fraction of the negative cases..
334 ((base-string simple-base-string simple-string)
335 (if (stringp host-object)
336 (warn-and-give-up)
337 (values nil t)))
338 ((vector simple-vector)
339 (if (vectorp host-object)
340 (warn-and-give-up)
341 (values nil t)))
342 ((array simple-array)
343 (if (arrayp host-object)
344 (warn-and-give-up)
345 (values nil t)))
346 (function
347 (if (functionp host-object)
348 (warn-and-give-up)
349 (values nil t)))
350 ;; And the Common Lisp type system is complicated,
351 ;; and we don't try to implement everything.
352 (otherwise (warn-and-give-up)))))
353 ;; And the Common Lisp type system is complicated, and
354 ;; we don't try to implement everything.
356 (warn-and-give-up))))))
358 ;;; This is an incomplete TYPEP which runs at cross-compile time to
359 ;;; tell whether OBJECT is the host Lisp representation of a target
360 ;;; SBCL type specified by TARGET-TYPE-SPEC. It need make no pretense
361 ;;; to completeness, since it need only handle the cases which arise
362 ;;; when building SBCL itself, e.g. testing that range limits FOO and
363 ;;; BAR in (INTEGER FOO BAR) are INTEGERs.
364 (defun sb!xc:typep (host-object target-type-spec &optional (env nil env-p))
365 (declare (ignore env))
366 (declare (optimize (debug 0))) ; workaround for lp# 1498644
367 (aver (null env-p)) ; 'cause we're too lazy to think about it
368 (multiple-value-bind (opinion certain-p)
369 (cross-typep host-object target-type-spec)
370 ;; A program that calls TYPEP doesn't want uncertainty and
371 ;; probably can't handle it.
372 (if certain-p
373 opinion
374 (error "uncertain in SB!XC:TYPEP ~S ~S"
375 host-object
376 target-type-spec))))
378 ;;; This is an incomplete, portable implementation for use at
379 ;;; cross-compile time only.
380 (defun ctypep (obj ctype)
381 (check-type ctype ctype)
382 ;; There is at least one possible endless recursion in the
383 ;; cross-compiler type system: (SUBTYPEP NULL (OR UNKOWN0 UNKNOWN1)
384 ;; runs out of stack. The right way would probably be to not
385 ;; implement CTYPEP in terms of TYPE-SPECIFIER (:UNPARSE, that may
386 ;; call TYPE=, that in turn may call CTYPEP). Until then, pick a few
387 ;; cherries off.
388 (cond ((member-type-p ctype)
389 (if (member-type-member-p obj ctype)
390 (values t t)
391 (values nil t)))
392 ((union-type-p ctype)
393 (any/type #'ctypep obj (union-type-types ctype)))
394 ((array-type-p ctype)
395 ;; This is essentially just the ARRAY-TYPE case of %%TYPEP
396 ;; using !SPECIALIZED-ARRAY-ELEMENT-TYPE, not ARRAY-ELEMENT-TYPE.
397 (if (and (arrayp obj)
398 (case (array-type-complexp ctype)
399 ((t) (not (typep obj 'simple-array)))
400 ((nil) (typep obj 'simple-array)))
401 (or (eq (array-type-element-type ctype) *wild-type*)
402 (type= (specifier-type
403 (!specialized-array-element-type obj))
404 (array-type-specialized-element-type ctype)))
405 (or (eq (array-type-dimensions ctype) '*)
406 (and (= (length (array-type-dimensions ctype))
407 (array-rank obj)))
408 (every (lambda (required actual)
409 (or (eq required '*) (eql required actual)))
410 (array-type-dimensions ctype)
411 (array-dimensions obj))))
412 (values t t)
413 (values nil t)))
415 (let ( ;; the Common Lisp type specifier corresponding to CTYPE
416 (type (type-specifier ctype)))
417 (check-type type (or symbol cons))
418 (cross-typep obj type)))))
420 (defun ctype-of (x)
421 (typecase x
422 (function
423 (if (typep x 'generic-function)
424 ;; Since at cross-compile time we build a CLOS-free bootstrap
425 ;; version of SBCL, it's unclear how to explain to it what a
426 ;; generic function is.
427 (error "not implemented: cross CTYPE-OF generic function")
428 ;; There's no ANSI way to find out what the function is
429 ;; declared to be, so we just return the CTYPE for the
430 ;; most-general function.
431 *universal-fun-type*))
432 (symbol
433 (make-eql-type x))
434 (number
435 (ctype-of-number x))
436 (array
437 ;; It is critical not to inquire of the host for the array's element type.
438 (let ((etype (specifier-type (!specialized-array-element-type x))))
439 (make-array-type (array-dimensions x)
440 ;; complexp relies on the host implementation,
441 ;; but in practice any array for which we need to
442 ;; call ctype-of will be a simple-array.
443 :complexp (not (typep x 'simple-array))
444 :element-type etype
445 :specialized-element-type etype)))
446 (cons (specifier-type 'cons))
447 (character
448 (cond ((typep x 'standard-char)
449 ;; (Note that SBCL doesn't distinguish between BASE-CHAR and
450 ;; CHARACTER.)
451 (specifier-type 'base-char))
452 ((not (characterp x))
453 nil)
455 ;; Beyond this, there seems to be no portable correspondence.
456 (error "can't map host Lisp CHARACTER ~S to target Lisp" x))))
457 (structure!object
458 (find-classoid (uncross (class-name (class-of x))))) ; FIXME: TYPE-OF?
460 ;; There might be more cases which we could handle with
461 ;; sufficient effort; since all we *need* to handle are enough
462 ;; cases for bootstrapping, we don't try to be complete here,. If
463 ;; future maintainers make the bootstrap code more complicated,
464 ;; they can also add new cases here to handle it. -- WHN 2000-11-11
465 (error "can't handle ~S in cross CTYPE-OF" x))))