2c200f3899a954c506147d1f3df7860f4c533bb7
[sbcl.git] / src / code / typep.lisp
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
3 ;;;;
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.
9
10 (in-package "SB!KERNEL")
11
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)
17   #!+sb-doc
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.)
25   (%typep object type))
26
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)
30   (%%typep object
31            (if (ctype-p specifier)
32                specifier
33                (specifier-type specifier))))
34 (defun %%typep (object type)
35   (declare (type ctype type))
36   (etypecase type
37     (named-type
38      (ecase (named-type-name type)
39        ((* t) t)
40        ((nil) nil)))
41     (numeric-type
42      (and (numberp object)
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)
49                          (realpart object)
50                          object)))
51             (ecase (numeric-type-class type)
52               (integer (integerp num))
53               (rational (rationalp num))
54               (float
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))))
61               ((nil) t)))
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)))
68                                 (t (>= val low)))
69                           (cond ((null high) t)
70                                 ((listp high) (< val (car high)))
71                                 (t (<= val high)))))))
72             (ecase (numeric-type-complexp type)
73               ((nil) t)
74               (:complex
75                (and (complexp object)
76                     (bound-test (realpart object))
77                     (bound-test (imagpart object))))
78               (:real
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))
85                          (> x y)))
86                    (signed->= (x y)
87                      (if (and (zerop x) (zerop y) (floatp x) (floatp y))
88                          (>= (float-sign x) (float-sign y))
89                          (>= x y)))
90                    (bound-test (val)
91                      (let ((low (numeric-type-low type))
92                            (high (numeric-type-high type)))
93                        (and (cond ((null low) t)
94                                   ((listp low)
95                                    (signed-> val (car low)))
96                                   (t
97                                    (signed->= val low)))
98                             (cond ((null high) t)
99                                   ((listp high)
100                                    (signed-> (car high) val))
101                                   (t
102                                    (signed->= high val)))))))
103             (ecase (numeric-type-complexp type)
104               ((nil) t)
105               (:complex
106                (and (complexp object)
107                     (bound-test (realpart object))
108                     (bound-test (imagpart object))))
109               (:real
110                (and (not (complexp object))
111                     (bound-test object)))))))
112     (array-type
113      (and (arrayp object)
114           (ecase (array-type-complexp type)
115             ((t) (not (typep object 'simple-array)))
116             ((nil) (typep object 'simple-array))
117             ((:maybe) t))
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))))
125                   (return nil))))
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))
131               t)
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
135                                               object)))))))
136     (member-type
137      (if (member object (member-type-members type)) t))
138     (classoid
139      #+sb-xc-host (ctypep object type)
140      #-sb-xc-host (classoid-typep (layout-of object) type object))
141     (union-type
142      (some (lambda (union-type-type) (%%typep object union-type-type))
143            (union-type-types type)))
144     (intersection-type
145      (every (lambda (intersection-type-type)
146               (%%typep object intersection-type-type))
147             (intersection-type-types type)))
148     (cons-type
149      (and (consp object)
150           (%%typep (car object) (cons-type-car-type type))
151           (%%typep (cdr object) (cons-type-cdr-type type))))
152     (unknown-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))))
161     (negation-type
162      (not (%%typep object (negation-type-type type))))
163     (hairy-type
164      ;; Now the tricky stuff.
165      (let* ((hairy-spec (hairy-type-specifier type))
166             (symbol (car hairy-spec)))
167        (ecase symbol
168          (and
169           (every (lambda (spec) (%%typep object (specifier-type spec)))
170                  (rest hairy-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.
175          (not
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)))))
179          (satisfies
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))))))
183     (alien-type-type
184      (sb!alien-internals:alien-typep object (alien-type-type-alien-type type)))
185     (fun-type
186      (error "Function types are not a legal argument to TYPEP:~%  ~S"
187             (type-specifier type)))))
188
189 ;;; Do a type test from a class cell, allowing forward reference and
190 ;;; redefinition.
191 (defun classoid-cell-typep (obj-layout cell object)
192   (let ((classoid (classoid-cell-classoid cell)))
193     (unless classoid
194       (error "The class ~S has not yet been defined."
195              (classoid-cell-name cell)))
196     (classoid-typep obj-layout classoid object)))
197
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)
213             (return t))))))
214
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)
218   object)