1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 (in-package "SB!KERNEL")
12 ;;; (Note that when cross-compiling, SB!XC:TYPEP is interpreted as a
13 ;;; test that the host Lisp object OBJECT translates to a target SBCL
14 ;;; type TYPE. This behavior is needed e.g. to test for the validity
15 ;;; of numeric subtype bounds read when cross-compiling.)
16 (defun typep (object type
&optional environment
)
18 "Is OBJECT of type TYPE?"
19 (declare (ignore environment
))
20 ;; Actually interpreting types at runtime is done by %TYPEP. The
21 ;; cost of the extra function call here should be negligible
22 ;; compared to the cost of interpreting types. (And the compiler
23 ;; tries hard to optimize away the interpretation of types at
24 ;; runtime, and when it succeeds, we never get here anyway.)
27 ;;; the actual TYPEP engine. The compiler only generates calls to this
28 ;;; function when it can't figure out anything more intelligent to do.
29 (defun %typep
(object specifier
)
31 (if (ctype-p specifier
)
33 (specifier-type specifier
))))
34 (defun %%typep
(object type
)
35 (declare (type ctype type
))
38 (ecase (named-type-name type
)
43 (let (;; I think this works because of an invariant of the
44 ;; two components of a COMPLEX are always coerced to
45 ;; be the same, e.g. (COMPLEX 1.0 3/2) => #C(1.0 1.5).
46 ;; Dunno why that holds, though -- ANSI? Python
47 ;; tradition? marsh faerie spirits? -- WHN 2001-10-27
48 (num (if (complexp object
)
51 (ecase (numeric-type-class type
)
52 (integer (integerp num
))
53 (rational (rationalp num
))
55 (ecase (numeric-type-format type
)
56 (short-float (typep num
'short-float
))
57 (single-float (typep num
'single-float
))
58 (double-float (typep num
'double-float
))
59 (long-float (typep num
'long-float
))
60 ((nil) (floatp num
))))
62 #!-negative-zero-is-not-zero
63 (flet ((bound-test (val)
64 (let ((low (numeric-type-low type
))
65 (high (numeric-type-high type
)))
66 (and (cond ((null low
) t
)
67 ((listp low
) (> val
(car low
)))
70 ((listp high
) (< val
(car high
)))
71 (t (<= val high
)))))))
72 (ecase (numeric-type-complexp type
)
75 (and (complexp object
)
76 (bound-test (realpart object
))
77 (bound-test (imagpart object
))))
79 (and (not (complexp object
))
80 (bound-test object
)))))
81 #!+negative-zero-is-not-zero
82 (labels ((signed-> (x y
)
83 (if (and (zerop x
) (zerop y
) (floatp x
) (floatp y
))
84 (> (float-sign x
) (float-sign y
))
87 (if (and (zerop x
) (zerop y
) (floatp x
) (floatp y
))
88 (>= (float-sign x
) (float-sign y
))
91 (let ((low (numeric-type-low type
))
92 (high (numeric-type-high type
)))
93 (and (cond ((null low
) t
)
95 (signed-> val
(car low
)))
100 (signed-> (car high
) val
))
102 (signed->= high val
)))))))
103 (ecase (numeric-type-complexp type
)
106 (and (complexp object
)
107 (bound-test (realpart object
))
108 (bound-test (imagpart object
))))
110 (and (not (complexp object
))
111 (bound-test object
)))))))
114 (ecase (array-type-complexp type
)
115 ((t) (not (typep object
'simple-array
)))
116 ((nil) (typep object
'simple-array
))
118 (or (eq (array-type-dimensions type
) '*)
119 (do ((want (array-type-dimensions type
) (cdr want
))
120 (got (array-dimensions object
) (cdr got
)))
121 ((and (null want
) (null got
)) t
)
122 (unless (and want got
123 (or (eq (car want
) '*)
124 (= (car want
) (car got
))))
126 (if (unknown-type-p (array-type-element-type type
))
127 ;; better to fail this way than to get bogosities like
128 ;; (TYPEP (MAKE-ARRAY 11) '(ARRAY SOME-UNDEFINED-TYPE)) => T
129 (error "~@<unknown element type in array type: ~2I~_~S~:>"
130 (type-specifier type
))
132 (or (eq (array-type-element-type type
) *wild-type
*)
133 (values (type= (array-type-specialized-element-type type
)
134 (specifier-type (array-element-type
137 (if (member object
(member-type-members type
)) t
))
139 #+sb-xc-host
(ctypep object type
)
140 #-sb-xc-host
(classoid-typep (layout-of object
) type object
))
142 (some (lambda (union-type-type) (%%typep object union-type-type
))
143 (union-type-types type
)))
145 (every (lambda (intersection-type-type)
146 (%%typep object intersection-type-type
))
147 (intersection-type-types type
)))
150 (%%typep
(car object
) (cons-type-car-type type
))
151 (%%typep
(cdr object
) (cons-type-cdr-type type
))))
153 ;; dunno how to do this ANSIly -- WHN 19990413
154 #+sb-xc-host
(error "stub: %%TYPEP UNKNOWN-TYPE in xcompilation host")
155 ;; Parse it again to make sure it's really undefined.
156 (let ((reparse (specifier-type (unknown-type-specifier type
))))
157 (if (typep reparse
'unknown-type
)
158 (error "unknown type specifier: ~S"
159 (unknown-type-specifier reparse
))
160 (%%typep object reparse
))))
162 (not (%%typep object
(negation-type-type type
))))
164 ;; Now the tricky stuff.
165 (let* ((hairy-spec (hairy-type-specifier type
))
166 (symbol (car hairy-spec
)))
169 (every (lambda (spec) (%%typep object
(specifier-type spec
)))
171 ;; Note: it should be safe to skip OR here, because union
172 ;; types can always be represented as UNION-TYPE in general
173 ;; or other CTYPEs in special cases; we never need to use
174 ;; HAIRY-TYPE for them.
176 (unless (proper-list-of-length-p hairy-spec
2)
177 (error "invalid type specifier: ~S" hairy-spec
))
178 (not (%%typep object
(specifier-type (cadr hairy-spec
)))))
180 (unless (proper-list-of-length-p hairy-spec
2)
181 (error "invalid type specifier: ~S" hairy-spec
))
182 (values (funcall (symbol-function (cadr hairy-spec
)) object
))))))
184 (sb!alien-internals
:alien-typep object
(alien-type-type-alien-type type
)))
186 (error "Function types are not a legal argument to TYPEP:~% ~S"
187 (type-specifier type
)))))
189 ;;; Do a type test from a class cell, allowing forward reference and
191 (defun classoid-cell-typep (obj-layout cell object
)
192 (let ((classoid (classoid-cell-classoid cell
)))
194 (error "The class ~S has not yet been defined."
195 (classoid-cell-name cell
)))
196 (classoid-typep obj-layout classoid object
)))
198 ;;; Test whether OBJ-LAYOUT is from an instance of CLASSOID.
199 (defun classoid-typep (obj-layout classoid object
)
200 (declare (optimize speed
))
201 (when (layout-invalid obj-layout
)
202 (if (and (typep (classoid-of object
) 'standard-classoid
) object
)
203 (setq obj-layout
(sb!pcl
::check-wrapper-validity object
))
204 (error "TYPEP was called on an obsolete object (was class ~S)."
205 (classoid-proper-name (layout-classoid obj-layout
)))))
206 (let ((layout (classoid-layout classoid
))
207 (obj-inherits (layout-inherits obj-layout
)))
208 (when (layout-invalid layout
)
209 (error "The class ~S is currently invalid." classoid
))
210 (or (eq obj-layout layout
)
211 (dotimes (i (length obj-inherits
) nil
)
212 (when (eq (svref obj-inherits i
) layout
)
215 ;;; This implementation is a placeholder to use until PCL is set up,
216 ;;; at which time it will be overwritten by a real implementation.
217 (defun sb!pcl
::check-wrapper-validity
(object)