`(%typep ,object ',spec))
(t
(ecase (first spec)
- (satisfies `(if (funcall #',(second spec) ,object) t nil))
+ (satisfies
+ `(if (funcall (global-function ,(second spec)) ,object) t nil))
((not and)
(once-only ((n-obj object))
`(,(first spec) ,@(mapcar (lambda (x)
;;; specified by TYPE, where STYPE is the type we have checked against
;;; (which is the same but for dimensions and element type).
;;;
-;;; Secondary return value is true if generated tests passing imply
-;;; that the array has a header.
+;;; Secondary return value is true if passing the generated tests implies that
+;;; the array has a header.
(defun test-array-dimensions (obj type stype)
(declare (type array-type type stype))
(let ((obj `(truly-the ,(type-specifier stype) ,obj))
(= (%array-rank ,obj) 0))
t))
((not (array-type-complexp type))
- (values (unless (eq '* (car dims))
- `((= (vector-length ,obj) ,@dims)))
- nil))
+ (if (csubtypep stype (specifier-type 'vector))
+ (values (unless (eq '* (car dims))
+ `((= (vector-length ,obj) ,@dims)))
+ nil)
+ (values (if (eq '* (car dims))
+ `((not (array-header-p ,obj)))
+ `((not (array-header-p ,obj))
+ (= (vector-length ,obj) ,@dims)))
+ nil)))
(t
(values (unless (eq '* (car dims))
`((if (array-header-p ,obj)
(deftransform coerce ((x type) (* *) * :node node)
(unless (constant-lvar-p type)
(give-up-ir1-transform))
- (let ((tspec (ir1-transform-specifier-type (lvar-value type))))
+ (let* ((tval (lvar-value type))
+ (tspec (ir1-transform-specifier-type tval)))
(if (csubtypep (lvar-type x) tspec)
'x
;; Note: The THE here makes sure that specifiers like
;; FIXME: #!+long-float (t ,(error "LONG-FLOAT case needed"))
((csubtypep tspec (specifier-type 'float))
'(%single-float x))
- ((and (csubtypep tspec (specifier-type 'simple-vector))
- ;; Can we avoid checking for dimension issues like
- ;; (COERCE FOO '(SIMPLE-VECTOR 5)) returning a
- ;; vector of length 6?
- (or (policy node (< safety 3)) ; no need in unsafe code
- (and (array-type-p tspec) ; no need when no dimensions
- (equal (array-type-dimensions tspec) '(*)))))
- `(if (simple-vector-p x)
+ ;; Special case STRING and SIMPLE-STRING as they are union types
+ ;; in SBCL.
+ ((member tval '(string simple-string))
+ `(if (typep x ',tval)
+ x
+ (replace (make-array (length x) :element-type 'character) x)))
+ ;; Special case VECTOR
+ ((eq tval 'vector)
+ `(if (vectorp x)
x
(replace (make-array (length x)) x)))
- ;; FIXME: other VECTOR types?
+ ;; Handle specialized element types for 1D arrays.
+ ((csubtypep tspec (specifier-type '(array * (*))))
+ ;; Can we avoid checking for dimension issues like (COERCE FOO
+ ;; '(SIMPLE-VECTOR 5)) returning a vector of length 6?
+ (if (or (policy node (< safety 3)) ; no need in unsafe code
+ (and (array-type-p tspec) ; no need when no dimensions
+ (equal (array-type-dimensions tspec) '(*))))
+ ;; We can!
+ (let ((array-type
+ (if (csubtypep tspec (specifier-type 'simple-array))
+ 'simple-array
+ 'array)))
+ (dolist (etype
+ #+sb-xc-host '(t bit character)
+ #-sb-xc-host sb!kernel::*specialized-array-element-types*
+ (give-up-ir1-transform))
+ (when etype
+ (let ((spec `(,array-type ,etype (*))))
+ (when (csubtypep tspec (specifier-type spec))
+ ;; Is the result required to be non-simple?
+ (let ((result-simple
+ (or (eq 'simple-array array-type)
+ (neq *empty-type*
+ (type-intersection
+ tspec (specifier-type 'simple-array))))))
+ (return
+ `(if (typep x ',spec)
+ x
+ (replace
+ (make-array (length x) :element-type ',etype
+ ,@(unless result-simple
+ (list :fill-pointer t
+ :adjustable t)))
+ x)))))))))
+ ;; No, duh. Dimension checking required.
+ (give-up-ir1-transform
+ "~@<~S specifies dimensions other than (*) in safe code.~:@>"
+ tval)))
(t
- (give-up-ir1-transform)))))))
-
-
+ (give-up-ir1-transform
+ "~@<open coding coercion to ~S not implemented.~:@>"
+ tval)))))))