1 ;;;; COERCE and related code
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!IMPL")
14 (macrolet ((def (name result access src-type &optional typep)
15 `(defun ,name (object ,@(if typep '(type) ()))
16 (declare (type ,(ecase src-type
19 (:sequence 'sequence)) object))
20 (do* ((index 0 (1+ index))
21 (length (length object))
24 ((>= index length) result)
25 (declare (fixnum length index))
26 (declare (type vector result))
27 (setf (,access result index)
29 (:list '(pop in-object))
30 (:vector '(aref in-object index))
31 (:sequence '(elt in-object index))))))))
33 (def list-to-vector* (make-sequence type length)
36 (def vector-to-vector* (make-sequence type length)
39 (def sequence-to-vector* (make-sequence type length)
42 (defun vector-to-list* (object)
43 (declare (type vector object))
44 (let ((result (list nil))
45 (length (length object)))
46 (declare (fixnum length))
47 (do ((index 0 (1+ index))
48 (splice result (cdr splice)))
49 ((>= index length) (cdr result))
50 (declare (fixnum index))
51 (rplacd splice (list (aref object index))))))
53 (defvar *offending-datum*); FIXME: Remove after debugging COERCE.
55 ;;; These are used both by the full DEFUN function and by various
56 ;;; optimization transforms in the constant-OUTPUT-TYPE-SPEC case.
58 ;;; Most of them are INLINE so that they can be optimized when the
59 ;;; argument type is known. It might be better to do this with
60 ;;; DEFTRANSFORMs, though.
61 (declaim (inline coerce-to-list))
62 (declaim (inline coerce-to-vector))
63 (defun coerce-to-fun (object)
64 ;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
65 ;; it's so big and because optimizing away the outer ETYPECASE
66 ;; doesn't seem to buy us that much anyway.)
69 ;; ANSI lets us return ordinary errors (non-TYPE-ERRORs) here.
70 (cond ((macro-function object)
71 (error "~S names a macro." object))
72 ((special-operator-p object)
73 (error "~S is a special operator." object))
74 (t (fdefinition object))))
80 ;; FIXME: If we go to a compiler-only implementation, this can
81 ;; become COMPILE instead of EVAL, which seems nicer to me.
82 (eval `(function ,object)))
84 (deprecation-error "0.9.3.32" 'instance-lambda 'lambda))
86 (error 'simple-type-error
88 :expected-type '(or symbol
89 ;; KLUDGE: ANSI wants us to
90 ;; return a TYPE-ERROR here, and
91 ;; a TYPE-ERROR is supposed to
92 ;; describe the expected type,
93 ;; but it's not obvious how to
94 ;; describe the coerceable cons
95 ;; types, so we punt and just say
96 ;; CONS. -- WHN 20000503
98 :format-control "~S can't be coerced to a function."
99 :format-arguments (list object)))))))
101 (defun coerce-to-list (object)
103 (vector (vector-to-list* object))))
105 (defun coerce-to-vector (object output-type-spec)
107 (list (list-to-vector* object output-type-spec))
108 (vector (vector-to-vector* object output-type-spec))))
110 ;;; old working version
111 (defun coerce (object output-type-spec)
113 "Coerce the Object to an object of type Output-Type-Spec."
114 (flet ((coerce-error ()
115 (/show0 "entering COERCE-ERROR")
116 (error 'simple-type-error
117 :format-control "~S can't be converted to type ~S."
118 :format-arguments (list object output-type-spec)
120 :expected-type output-type-spec)))
121 (let ((type (specifier-type output-type-spec)))
123 ((%typep object output-type-spec)
125 ((eq type *empty-type*)
127 ((csubtypep type (specifier-type 'character))
131 ((csubtypep type (specifier-type 'single-float))
132 (let ((res (%single-float object)))
133 (unless (typep res output-type-spec)
136 ((csubtypep type (specifier-type 'double-float))
137 (let ((res (%double-float object)))
138 (unless (typep res output-type-spec)
142 ((csubtypep type (specifier-type 'long-float))
143 (let ((res (%long-float object)))
144 (unless (typep res output-type-spec)
147 ((csubtypep type (specifier-type 'float))
148 (let ((res (%single-float object)))
149 (unless (typep res output-type-spec)
155 ((csubtypep type (specifier-type '(complex single-float)))
156 (complex (%single-float (realpart object))
157 (%single-float (imagpart object))))
158 ((csubtypep type (specifier-type '(complex double-float)))
159 (complex (%double-float (realpart object))
160 (%double-float (imagpart object))))
162 ((csubtypep type (specifier-type '(complex long-float)))
163 (complex (%long-float (realpart object))
164 (%long-float (imagpart object))))
165 ((csubtypep type (specifier-type '(complex float)))
166 (complex (%single-float (realpart object))
167 (%single-float (imagpart object))))
168 ((and (typep object 'rational)
169 (csubtypep type (specifier-type '(complex float))))
170 ;; Perhaps somewhat surprisingly, ANSI specifies
171 ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT,
172 ;; not dispatching on
173 ;; *READ-DEFAULT-FLOAT-FORMAT*. By analogy, we
174 ;; do the same for complex numbers. -- CSR,
176 (complex (%single-float object)))
177 ((csubtypep type (specifier-type 'complex))
181 ;; If RES has the wrong type, that means that rule of
182 ;; canonical representation for complex rationals was
183 ;; invoked. According to the Hyperspec, (coerce 7/2
184 ;; 'complex) returns 7/2. Thus, if the object was a
185 ;; rational, there is no error here.
186 (unless (or (typep res output-type-spec)
190 ((csubtypep type (specifier-type 'list))
193 ((type= type (specifier-type 'list))
194 (vector-to-list* object))
195 ((type= type (specifier-type 'null))
196 (if (= (length object) 0)
198 (sequence-type-length-mismatch-error type
201 (multiple-value-bind (min exactp)
202 (sb!kernel::cons-type-length-info type)
203 (let ((length (length object)))
205 (unless (= length min)
206 (sequence-type-length-mismatch-error type length))
207 (unless (>= length min)
208 (sequence-type-length-mismatch-error type length)))
209 (vector-to-list* object))))
210 (t (sequence-type-too-hairy (type-specifier type))))
211 (if (sequencep object)
213 ((type= type (specifier-type 'list))
214 (sb!sequence:make-sequence-like
215 nil (length object) :initial-contents object))
216 ((type= type (specifier-type 'null))
217 (if (= (length object) 0)
219 (sequence-type-length-mismatch-error type
222 (multiple-value-bind (min exactp)
223 (sb!kernel::cons-type-length-info type)
224 (let ((length (length object)))
226 (unless (= length min)
227 (sequence-type-length-mismatch-error type length))
228 (unless (>= length min)
229 (sequence-type-length-mismatch-error type length)))
230 (sb!sequence:make-sequence-like
231 nil length :initial-contents object))))
232 (t (sequence-type-too-hairy (type-specifier type))))
234 ((csubtypep type (specifier-type 'vector))
236 ;; FOO-TO-VECTOR* go through MAKE-SEQUENCE, so length
237 ;; errors are caught there. -- CSR, 2002-10-18
238 (list (list-to-vector* object output-type-spec))
239 (vector (vector-to-vector* object output-type-spec))
240 (sequence (sequence-to-vector* object output-type-spec))
243 ((and (csubtypep type (specifier-type 'sequence))
244 (find-class output-type-spec nil))
245 (let ((class (find-class output-type-spec)))
246 (sb!sequence:make-sequence-like
247 (sb!mop:class-prototype class)
248 (length object) :initial-contents object)))
249 ((csubtypep type (specifier-type 'function))
250 (when (and (legal-fun-name-p object)
251 (not (fboundp object)))
252 (error 'simple-type-error
254 ;; FIXME: SATISFIES FBOUNDP is a kinda bizarre broken
255 ;; type specifier, since the set of values it describes
256 ;; isn't in general constant in time. Maybe we could
257 ;; find a better way of expressing this error? (Maybe
258 ;; with the UNDEFINED-FUNCTION condition?)
259 :expected-type '(satisfies fboundp)
260 :format-control "~S isn't fbound."
261 :format-arguments (list object)))
262 (when (and (symbolp object)
263 (sb!xc:macro-function object))
264 (error 'simple-type-error
266 :expected-type '(not (satisfies sb!xc:macro-function))
267 :format-control "~S is a macro."
268 :format-arguments (list object)))
269 (when (and (symbolp object)
270 (special-operator-p object))
271 (error 'simple-type-error
273 :expected-type '(not (satisfies special-operator-p))
274 :format-control "~S is a special operator."
275 :format-arguments (list object)))
280 ;;; new version, which seems as though it should be better, but which
281 ;;; does not yet work
283 (defun coerce (object output-type-spec)
285 "Coerces the Object to an object of type Output-Type-Spec."
286 (flet ((coerce-error ()
287 (error 'simple-type-error
288 :format-control "~S can't be converted to type ~S."
289 :format-arguments (list object output-type-spec)))
290 (check-result (result)
291 #!+high-security (aver (typep result output-type-spec))
293 (let ((type (specifier-type output-type-spec)))
295 ((%typep object output-type-spec)
297 ((eq type *empty-type*)
299 ((csubtypep type (specifier-type 'character))
301 ((csubtypep type (specifier-type 'function))
302 (coerce-to-fun object))
306 ((csubtypep type (specifier-type 'single-float))
307 (%single-float object))
308 ((csubtypep type (specifier-type 'double-float))
309 (%double-float object))
311 ((csubtypep type (specifier-type 'long-float))
312 (%long-float object))
313 ((csubtypep type (specifier-type 'float))
314 (%single-float object))
315 ((csubtypep type (specifier-type '(complex single-float)))
316 (complex (%single-float (realpart object))
317 (%single-float (imagpart object))))
318 ((csubtypep type (specifier-type '(complex double-float)))
319 (complex (%double-float (realpart object))
320 (%double-float (imagpart object))))
322 ((csubtypep type (specifier-type '(complex long-float)))
323 (complex (%long-float (realpart object))
324 (%long-float (imagpart object))))
325 ((csubtypep type (specifier-type 'complex))
329 ;; If RES has the wrong type, that means that rule of
330 ;; canonical representation for complex rationals was
331 ;; invoked. According to the ANSI spec, (COERCE 7/2
332 ;; 'COMPLEX) returns 7/2. Thus, if the object was a
333 ;; rational, there is no error here.
334 (unless (or (typep res output-type-spec) (rationalp object))
337 ((csubtypep type (specifier-type 'list))
338 (coerce-to-list object))
339 ((csubtypep type (specifier-type 'string))
340 (check-result (coerce-to-simple-string object)))
341 ((csubtypep type (specifier-type 'bit-vector))
342 (check-result (coerce-to-bit-vector object)))
343 ((csubtypep type (specifier-type 'vector))
344 (check-result (coerce-to-vector object output-type-spec)))