Declare COERCE and two helpers as EXPLICIT-CHECK.
[sbcl.git] / src / code / coerce.lisp
blob913c0655178f1e4328b68f679877236fa18820c0
1 ;;;; COERCE and related code
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!IMPL")
14 (macrolet ((def (name constructor access src-type)
15 `(defun ,name (object type)
16 (declare (type ,src-type object))
17 (do* ((index 0 (1+ index))
18 (length (length object))
19 (result ,constructor)
20 (in-object object))
21 ((>= index length) result)
22 (declare (fixnum length index))
23 (declare (type vector result))
24 (setf (,access result index)
25 ,(ecase src-type
26 (list '(pop in-object))
27 (vector '(aref in-object index))
28 (sequence '(elt in-object index))))))))
30 (def list-to-vector* (make-sequence type length) aref list)
32 (def vector-to-vector* (make-sequence type length) aref vector)
34 (def sequence-to-vector* (make-sequence type length) aref sequence))
36 (defun vector-to-list* (object)
37 (declare (type vector object))
38 (let ((result (list nil))
39 (length (length object)))
40 (declare (fixnum length))
41 (do ((index 0 (1+ index))
42 (splice result (cdr splice)))
43 ((>= index length) (cdr result))
44 (declare (fixnum index))
45 (rplacd splice (list (aref object index))))))
47 (defun sequence-to-list (sequence)
48 (declare (type sequence sequence))
49 (let* ((result (list nil))
50 (splice result))
51 (sb!sequence:dosequence (i sequence)
52 (rplacd splice (list i))
53 (setf splice (cdr splice)))
54 (cdr result)))
56 ;;; These are used both by the full DEFUN function and by various
57 ;;; optimization transforms in the constant-OUTPUT-TYPE-SPEC case.
58 ;;;
59 ;;; Most of them are INLINE so that they can be optimized when the
60 ;;; argument type is known. It might be better to do this with
61 ;;; DEFTRANSFORMs, though.
62 (declaim (inline coerce-to-list))
63 (declaim (inline coerce-to-vector))
65 (defun coerce-symbol-to-fun (symbol)
66 ;; FIXME? I would think to use SYMBOL-FUNCTION here which does not strip off
67 ;; encapsulations. But Stas wrote FDEFINITION so ...
68 ;; [Also note, we won't encapsulate a macro or special-form, so this
69 ;; introspective technique to decide what kind something is works either way]
70 (let ((def (fdefinition symbol)))
71 (acond ((macro/special-guard-fun-p def)
72 (error (if (eq it :special)
73 "~S names a special operator." "~S names a macro.")
74 symbol))
75 (t def))))
77 (defun coerce-to-fun (object)
78 ;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
79 ;; it's so big and because optimizing away the outer ETYPECASE
80 ;; doesn't seem to buy us that much anyway.)
81 (etypecase object
82 (function object)
83 (symbol
84 (coerce-symbol-to-fun object))
85 (list
86 (case (first object)
87 (setf
88 (fdefinition object))
89 (lambda
90 (eval object))
92 (error 'simple-type-error
93 :datum object
94 :expected-type '(or symbol
95 ;; KLUDGE: ANSI wants us to
96 ;; return a TYPE-ERROR here, and
97 ;; a TYPE-ERROR is supposed to
98 ;; describe the expected type,
99 ;; but it's not obvious how to
100 ;; describe the coerceable cons
101 ;; types, so we punt and just say
102 ;; CONS. -- WHN 20000503
103 cons)
104 :format-control "~S can't be coerced to a function."
105 :format-arguments (list object)))))))
107 (defun coerce-to-list (object)
108 (seq-dispatch object
109 object
110 (vector-to-list* object)
111 (sequence-to-list object)))
113 (defun coerce-to-vector (object output-type-spec)
114 (etypecase object
115 (list (list-to-vector* object output-type-spec))
116 (vector (vector-to-vector* object output-type-spec))))
118 ;;; old working version
119 (defun coerce (object output-type-spec)
120 #!+sb-doc
121 "Coerce the Object to an object of type Output-Type-Spec."
122 (flet ((coerce-error ()
123 (error 'simple-type-error
124 :format-control "~S can't be converted to type ~S."
125 :format-arguments (list object output-type-spec)
126 :datum object
127 :expected-type output-type-spec)))
128 (let ((type (specifier-type output-type-spec)))
129 (cond
130 ((%%typep object type)
131 object)
132 ((eq type *empty-type*)
133 (coerce-error))
134 ((type= type (specifier-type 'character))
135 (character object))
136 ((numberp object)
137 (cond
138 ((csubtypep type (specifier-type 'single-float))
139 (let ((res (%single-float object)))
140 (unless (typep res output-type-spec)
141 (coerce-error))
142 res))
143 ((csubtypep type (specifier-type 'double-float))
144 (let ((res (%double-float object)))
145 (unless (typep res output-type-spec)
146 (coerce-error))
147 res))
148 #!+long-float
149 ((csubtypep type (specifier-type 'long-float))
150 (let ((res (%long-float object)))
151 (unless (typep res output-type-spec)
152 (coerce-error))
153 res))
154 ((csubtypep type (specifier-type 'float))
155 (let ((res (%single-float object)))
156 (unless (typep res output-type-spec)
157 (coerce-error))
158 res))
160 (let ((res
161 (cond
162 ((csubtypep type (specifier-type '(complex single-float)))
163 (complex (%single-float (realpart object))
164 (%single-float (imagpart object))))
165 ((csubtypep type (specifier-type '(complex double-float)))
166 (complex (%double-float (realpart object))
167 (%double-float (imagpart object))))
168 #!+long-float
169 ((csubtypep type (specifier-type '(complex long-float)))
170 (complex (%long-float (realpart object))
171 (%long-float (imagpart object))))
172 ((csubtypep type (specifier-type '(complex float)))
173 (complex (%single-float (realpart object))
174 (%single-float (imagpart object))))
175 ((and (typep object 'rational) ; TODO jmoringe unreachable?
176 (csubtypep type (specifier-type '(complex float))))
177 ;; Perhaps somewhat surprisingly, ANSI specifies
178 ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT,
179 ;; not dispatching on
180 ;; *READ-DEFAULT-FLOAT-FORMAT*. By analogy, we
181 ;; do the same for complex numbers. -- CSR,
182 ;; 2002-08-06
183 (complex (%single-float object)))
184 ((csubtypep type (specifier-type 'complex))
185 (complex object))
187 (coerce-error)))))
188 ;; If RES has the wrong type, that means that rule of
189 ;; canonical representation for complex rationals was
190 ;; invoked. According to the Hyperspec, (coerce 7/2
191 ;; 'complex) returns 7/2. Thus, if the object was a
192 ;; rational, there is no error here.
193 (unless (or (typep res output-type-spec)
194 (rationalp object))
195 (coerce-error))
196 res))))
197 ((csubtypep type (specifier-type 'list))
198 (if (vectorp object)
199 (cond
200 ((type= type (specifier-type 'list))
201 (vector-to-list* object))
202 ((type= type (specifier-type 'null))
203 (if (= (length object) 0)
204 'nil
205 (sequence-type-length-mismatch-error type
206 (length object))))
207 ((cons-type-p type)
208 (multiple-value-bind (min exactp)
209 (sb!kernel::cons-type-length-info type)
210 (let ((length (length object)))
211 (if exactp
212 (unless (= length min)
213 (sequence-type-length-mismatch-error type length))
214 (unless (>= length min)
215 (sequence-type-length-mismatch-error type length)))
216 (vector-to-list* object))))
217 (t (sequence-type-too-hairy (type-specifier type))))
218 (if (sequencep object)
219 (cond
220 ((type= type (specifier-type 'list))
221 (sb!sequence:make-sequence-like
222 nil (length object) :initial-contents object))
223 ((type= type (specifier-type 'null))
224 (if (= (length object) 0)
225 'nil
226 (sequence-type-length-mismatch-error type
227 (length object))))
228 ((cons-type-p type)
229 (multiple-value-bind (min exactp)
230 (sb!kernel::cons-type-length-info type)
231 (let ((length (length object)))
232 (if exactp
233 (unless (= length min)
234 (sequence-type-length-mismatch-error type length))
235 (unless (>= length min)
236 (sequence-type-length-mismatch-error type length)))
237 (sb!sequence:make-sequence-like
238 nil length :initial-contents object))))
239 (t (sequence-type-too-hairy (type-specifier type))))
240 (coerce-error))))
241 ((csubtypep type (specifier-type 'vector))
242 (typecase object
243 ;; FOO-TO-VECTOR* go through MAKE-SEQUENCE, so length
244 ;; errors are caught there. -- CSR, 2002-10-18
245 (list (list-to-vector* object output-type-spec))
246 (vector (vector-to-vector* object output-type-spec))
247 (sequence (sequence-to-vector* object output-type-spec))
249 (coerce-error))))
250 ((and (csubtypep type (specifier-type 'sequence))
251 (find-class output-type-spec nil))
252 (let ((prototype (sb!mop:class-prototype
253 (sb!pcl:ensure-class-finalized
254 (find-class output-type-spec)))))
255 (sb!sequence:make-sequence-like
256 prototype (length object) :initial-contents object)))
257 ((csubtypep type (specifier-type 'function))
258 (coerce-to-fun object))
260 (coerce-error))))))
262 ;;; new version, which seems as though it should be better, but which
263 ;;; does not yet work
264 #+nil
265 (defun coerce (object output-type-spec)
266 #!+sb-doc
267 "Coerces the Object to an object of type Output-Type-Spec."
268 (flet ((coerce-error ()
269 (error 'simple-type-error
270 :format-control "~S can't be converted to type ~S."
271 :format-arguments (list object output-type-spec)))
272 (check-result (result)
273 #!+high-security (aver (typep result output-type-spec))
274 result))
275 (let ((type (specifier-type output-type-spec)))
276 (cond
277 ((%%typep object type)
278 object)
279 ((eq type *empty-type*)
280 (coerce-error))
281 ((csubtypep type (specifier-type 'character))
282 (character object))
283 ((csubtypep type (specifier-type 'function))
284 (coerce-to-fun object))
285 ((numberp object)
286 (let ((res
287 (cond
288 ((csubtypep type (specifier-type 'single-float))
289 (%single-float object))
290 ((csubtypep type (specifier-type 'double-float))
291 (%double-float object))
292 #!+long-float
293 ((csubtypep type (specifier-type 'long-float))
294 (%long-float object))
295 ((csubtypep type (specifier-type 'float))
296 (%single-float object))
297 ((csubtypep type (specifier-type '(complex single-float)))
298 (complex (%single-float (realpart object))
299 (%single-float (imagpart object))))
300 ((csubtypep type (specifier-type '(complex double-float)))
301 (complex (%double-float (realpart object))
302 (%double-float (imagpart object))))
303 #!+long-float
304 ((csubtypep type (specifier-type '(complex long-float)))
305 (complex (%long-float (realpart object))
306 (%long-float (imagpart object))))
307 ((csubtypep type (specifier-type 'complex))
308 (complex object))
310 (coerce-error)))))
311 ;; If RES has the wrong type, that means that rule of
312 ;; canonical representation for complex rationals was
313 ;; invoked. According to the ANSI spec, (COERCE 7/2
314 ;; 'COMPLEX) returns 7/2. Thus, if the object was a
315 ;; rational, there is no error here.
316 (unless (or (typep res output-type-spec) (rationalp object))
317 (coerce-error))
318 res))
319 ((csubtypep type (specifier-type 'list))
320 (coerce-to-list object))
321 ((csubtypep type (specifier-type 'string))
322 (check-result (coerce-to-simple-string object)))
323 ((csubtypep type (specifier-type 'bit-vector))
324 (check-result (coerce-to-bit-vector object)))
325 ((csubtypep type (specifier-type 'vector))
326 (check-result (coerce-to-vector object output-type-spec)))
328 (coerce-error))))))