46:
type safety errors reported by Peter Van Eynde July 25, 2000:
- a: (COERCE (QUOTE (A B C)) (QUOTE (VECTOR * 4)))
- => #(A B C)
- In general lengths of array type specifications aren't
- checked by COERCE, so it fails when the spec is
- (VECTOR 4), (STRING 2), (SIMPLE-BIT-VECTOR 3), or whatever.
- b: CONCATENATE has the same problem of not checking the length
- of specified output array types. MAKE-SEQUENCE and MAP and
- MERGE also have the same problem.
c: (COERCE 'AND 'FUNCTION) returns something related to
(MACRO-FUNCTION 'AND), but ANSI says it should raise an error.
h: (MAKE-CONCATENATED-STREAM (MAKE-STRING-OUTPUT-STREAM))
the new output block should start indented 2 or more characters
rightward of the correct location.
-66:
- ANSI specifies that the RESULT-TYPE argument of CONCATENATE must be
- a subtype of SEQUENCE, but CONCATENATE doesn't check this properly:
- (CONCATENATE 'SIMPLE-ARRAY #(1 2) '(3)) => #(1 2 3)
- This also leads to funny behavior when derived type specifiers
- are used, as originally reported by Milan Zamazal for CMU CL (on the
- Debian bugs mailing list (?) 2000-02-27), then reported by Martin
- Atzmueller for SBCL (2000-10-01 on sbcl-devel@lists.sourceforge.net):
- (DEFTYPE FOO () 'SIMPLE-ARRAY)
- (CONCATENATE 'FOO #(1 2) '(3))
- => #<ARRAY-TYPE SIMPLE-ARRAY> is a bad type specifier for
- sequence functions.
- The derived type specifier FOO should act the same way as the
- built-in type SIMPLE-ARRAY here, but it doesn't. That problem
- doesn't seem to exist for sequence types:
- (DEFTYPE BAR () 'SIMPLE-VECTOR)
- (CONCATENATE 'BAR #(1 2) '(3)) => #(1 2 3)
- See also bug #46a./b., and discussion and patch sbcl-devel and
- cmucl-imp 2002-07
-
67:
As reported by Winton Davies on a CMU CL mailing list 2000-01-10,
and reported for SBCL by Martin Atzmueller 2000-10-20: (TRACE GETHASH)
"CODE-COMPONENT" "CODE-COMPONENT-P"
"CODE-DEBUG-INFO" "CODE-HEADER-REF" "CODE-HEADER-SET"
"CODE-INSTRUCTIONS"
- "COERCE-TO-BIT-VECTOR" "COERCE-TO-FUN" "COERCE-TO-LEXENV"
- "COERCE-TO-LIST" "COERCE-TO-SIMPLE-STRING"
- "COERCE-TO-SIMPLE-VECTOR" "COERCE-TO-VECTOR"
+ "COERCE-TO-FUN" "COERCE-TO-LEXENV"
+ "COERCE-TO-LIST" "COERCE-TO-VECTOR"
"*COLD-INIT-COMPLETE-P*"
"COMPLEX-DOUBLE-FLOAT-P"
"COMPLEX-FLOAT-P" "COMPLEX-LONG-FLOAT-P"
"ANSI-STREAM-IN-INDEX"
"ANSI-STREAM-MISC" "ANSI-STREAM-N-BIN"
"ANSI-STREAM-OUT" "ANSI-STREAM-SOUT"
- "LIST-TO-SIMPLE-STRING*" "LIST-TO-BIT-VECTOR*"
"LIST-TO-VECTOR*"
"LOGICAL-HOST" "LOGICAL-HOST-DESIGNATOR"
"LONG-FLOAT-EXPONENT" "LONG-FLOAT-EXP-BITS"
"VALUES-TYPE-P" "VALUES-TYPE-REQUIRED"
"VALUES-TYPE-REST" "VALUES-TYPE-UNION"
"VALUES-TYPES" "VALUES-TYPES-EQUAL-OR-INTERSECT" "VECTOR-T-P"
- "VECTOR-TO-VECTOR*" "VECTOR-TO-SIMPLE-STRING*"
- "VECTOR-TO-BIT-VECTOR*" "VECTOR-TO-SIMPLE-BIT-VECTOR*"
+ "VECTOR-TO-VECTOR*"
"VECTOR-OF-CHECKED-LENGTH-GIVEN-LENGTH"
"WITH-ARRAY-DATA"
"WRONG-NUMBER-OF-INDICES-ERROR"
(inherits-list (second x))
(class (make-standard-class :name name))
(class-cell (find-class-cell name)))
+ ;; Needed to open-code the MAP, below
+ (declare (type list inherits-list))
(setf (class-cell-class class-cell) class
(info :type :class name) class-cell
(info :type :kind name) :instance)
(:list '(pop in-object))
(:vector '(aref in-object index))))))))
- (def list-to-simple-string* (make-string length) schar :list)
-
- (def list-to-bit-vector* (make-array length :element-type '(mod 2))
- sbit :list)
-
- (def list-to-vector* (make-sequence-of-type type length)
+ (def list-to-vector* (make-sequence type length)
aref :list t)
- (def vector-to-vector* (make-sequence-of-type type length)
- aref :vector t)
-
- (def vector-to-simple-string* (make-string length) schar :vector)
-
- (def vector-to-bit-vector* (make-array length :element-type '(mod 2))
- sbit :vector))
+ (def vector-to-vector* (make-sequence type length)
+ aref :vector t))
(defun vector-to-list* (object)
(let ((result (list nil))
(declare (fixnum index))
(rplacd splice (list (aref object index))))))
-(defun string-to-simple-string* (object)
- (if (simple-string-p object)
- object
- (with-array-data ((data object)
- (start)
- (end (length object)))
- (declare (simple-string data))
- (subseq data start end))))
-
-(defun bit-vector-to-simple-bit-vector* (object)
- (if (simple-bit-vector-p object)
- object
- (with-array-data ((data object)
- (start)
- (end (length object)))
- (declare (simple-bit-vector data))
- (subseq data start end))))
-
(defvar *offending-datum*); FIXME: Remove after debugging COERCE.
;;; These are used both by the full DEFUN function and by various
;;; argument type is known. It might be better to do this with
;;; DEFTRANSFORMs, though.
(declaim (inline coerce-to-list))
-(declaim (inline coerce-to-simple-string coerce-to-bit-vector coerce-to-vector))
+(declaim (inline coerce-to-vector))
(defun coerce-to-fun (object)
;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
;; it's so big and because optimizing away the outer ETYPECASE
cons)
:format-control "~S can't be coerced to a function."
:format-arguments (list object)))))))
+
(defun coerce-to-list (object)
(etypecase object
(vector (vector-to-list* object))))
-(defun coerce-to-simple-string (object)
- (etypecase object
- (list (list-to-simple-string* object))
- (string (string-to-simple-string* object))
- (vector (vector-to-simple-string* object))))
-(defun coerce-to-bit-vector (object)
- (etypecase object
- (list (list-to-bit-vector* object))
- (vector (vector-to-bit-vector* object))))
-(defun coerce-to-simple-vector (x)
- (if (simple-vector-p x)
- x
- (replace (make-array (length x)) x)))
+
(defun coerce-to-vector (object output-type-spec)
(etypecase object
(list (list-to-vector* object output-type-spec))
(/show0 "entering COERCE-ERROR")
(error 'simple-type-error
:format-control "~S can't be converted to type ~S."
- :format-arguments (list object output-type-spec)))
- (check-result (result)
- #!+high-security (aver (typep result output-type-spec))
- result))
+ :format-arguments (list object output-type-spec))))
(let ((type (specifier-type output-type-spec)))
(cond
((%typep object output-type-spec)
(if (vectorp object)
(vector-to-list* object)
(coerce-error)))
- ((csubtypep type (specifier-type 'string))
- (check-result
- (typecase object
- (list (list-to-simple-string* object))
- (string (string-to-simple-string* object))
- (vector (vector-to-simple-string* object))
- (t
- (coerce-error)))))
- ((csubtypep type (specifier-type 'bit-vector))
- (check-result
- (typecase object
- (list (list-to-bit-vector* object))
- (vector (vector-to-bit-vector* object))
- (t
- (coerce-error)))))
((csubtypep type (specifier-type 'vector))
- (check-result
- (typecase object
- (list (list-to-vector* object output-type-spec))
- (vector (vector-to-vector* object output-type-spec))
- (t
- (coerce-error)))))
+ (typecase object
+ (list (list-to-vector* object output-type-spec))
+ (vector (vector-to-vector* object output-type-spec))
+ (t
+ (coerce-error))))
(t
(coerce-error))))))
;;; versions which break binary compatibility. But it certainly should
;;; be incremented for release versions which break binary
;;; compatibility.
-(def!constant +fasl-file-version+ 32)
+(def!constant +fasl-file-version+ 33)
;;; (record of versions before 0.7.0 deleted in 0.7.1.41)
;;; 23 = sbcl-0.7.0.1 deleted no-longer-used EVAL-STACK stuff,
;;; causing changes in *STATIC-SYMBOLS*.
;;; is currently external to its package
;;; 32: (2002-09-21) changes in implementation of sequence functions,
;;; causing old utility functions like COERCE-TO-SIMPLE-VECTOR to go away
+;;; 33: (2002-10-02) (again) changes in implementation of sequence functions,
+;;; causing old utility functions like COERCE-TO-SIMPLE-VECTOR to go away
;;; the conventional file extension for our fasl files
(declaim (type simple-string *fasl-file-type*))
;;; producing a symbol in the current package.
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun symbolicate (&rest things)
- (values (intern (apply #'concatenate
- 'string
- (mapcar #'string things))))))
+ (let ((name (case (length things)
+ ;; why isn't this just the value in the T branch?
+ ;; Well, this is called early in cold-init, before
+ ;; the type system is set up; however, now that we
+ ;; check for bad lengths, the type system is needed
+ ;; for calls to CONCATENATE. So we need to make sure
+ ;; that the calls are transformed away:
+ (1 (concatenate 'string (the simple-string (string (car things)))))
+ (2 (concatenate 'string
+ (the simple-string (string (car things)))
+ (the simple-string (string (cadr things)))))
+ (3 (concatenate 'string
+ (the simple-string (string (car things)))
+ (the simple-string (string (cadr things)))
+ (the simple-string (string (caddr things)))))
+ (t (apply #'concatenate 'string (mapcar #'string things))))))
+ (values (intern name)))))
;;; like SYMBOLICATE, but producing keywords
(defun keywordicate (&rest things)
;;;
;;; FIXME: It might be worth making three cases here, LIST,
;;; SIMPLE-VECTOR, and VECTOR, instead of the current LIST and VECTOR.
-;;; It tend to make code run faster but be bigger; some benchmarking
+;;; It tends to make code run faster but be bigger; some benchmarking
;;; is needed to decide.
(sb!xc:defmacro seq-dispatch (sequence list-form array-form)
`(if (listp ,sequence)
(sb!xc:defmacro make-sequence-like (sequence length)
#!+sb-doc
"Return a sequence of the same type as SEQUENCE and the given LENGTH."
- `(make-sequence-of-type (type-of ,sequence) ,length))
-
-(sb!xc:defmacro type-specifier-atom (type)
- #!+sb-doc "Return the broad class of which TYPE is a specific subclass."
- `(if (atom ,type) ,type (car ,type)))
+ `(if (typep ,sequence 'list)
+ (make-list ,length)
+ (progn
+ ;; This is only called from places which have already deduced
+ ;; that the SEQUENCE argument is actually a sequence. So
+ ;; this would be a candidate place for (AVER (TYPEP ,SEQUENCE
+ ;; 'VECTOR)), except that this seems to be a performance
+ ;; hotspot.
+ (make-array ,length
+ :element-type (array-element-type ,sequence)))))
+
+(sb!xc:defmacro bad-sequence-type-error (type-spec)
+ `(error 'simple-type-error
+ :datum ,type-spec
+ ;; FIXME: This is actually wrong, and should be something
+ ;; like (SATISFIES IS-A-VALID-SEQUENCE-TYPE-SPECIFIER-P).
+ :expected-type 'sequence
+ :format-control "~S is a bad type specifier for sequences."
+ :format-arguments (list ,type-spec)))
) ; EVAL-WHEN
(vector-of-checked-length-given-length sequence
declared-length))))))
-;;; Given an arbitrary type specifier, return a sane sequence type
-;;; specifier that we can directly match.
-(defun result-type-or-lose (type &optional nil-ok)
- (let ((type (specifier-type type)))
- (cond
- ((eq type *empty-type*)
- (if nil-ok
- nil
- (error 'simple-type-error
- :datum type
- :expected-type '(or vector cons)
- :format-control
- "A NIL output type is invalid for this sequence function."
- :format-arguments ())))
- ((dolist (seq-type '(list string simple-vector bit-vector))
- (when (csubtypep type (specifier-type seq-type))
- (return seq-type))))
- ((csubtypep type (specifier-type 'vector))
- (type-specifier type))
- (t
- (error 'simple-type-error
- :datum type
- :expected-type 'sequence
- :format-control
- "~S is not a legal type specifier for sequence functions."
- :format-arguments (list type))))))
-
(defun signal-index-too-large-error (sequence index)
(let* ((length (length sequence))
(max-index (and (plusp length)
`(integer 0 ,max-end)
;; This seems silly, is there something better?
'(integer (0) 0)))))
-
-(defun make-sequence-of-type (type length)
- #!+sb-doc "Return a sequence of the given TYPE and LENGTH."
- (declare (fixnum length))
- (case (type-specifier-atom type)
- (list (make-list length))
- ((bit-vector simple-bit-vector) (make-array length :element-type '(mod 2)))
- ((string simple-string base-string simple-base-string)
- (make-string length))
- (simple-vector (make-array length))
- ((array simple-array vector)
- (if (listp type)
- (make-array length :element-type (cadr type))
- (make-array length)))
- (t
- (make-sequence-of-type (result-type-or-lose type) length))))
\f
(defun elt (sequence index)
#!+sb-doc "Return the element of SEQUENCE specified by INDEX."
(let ((type (specifier-type type)))
(cond ((csubtypep type (specifier-type 'list))
(make-list length :initial-element initial-element))
- ((csubtypep type (specifier-type 'string))
- (if iep
- (make-string length :initial-element initial-element)
- (make-string length)))
- ((csubtypep type (specifier-type 'simple-vector))
- (make-array length :initial-element initial-element))
- ((csubtypep type (specifier-type 'bit-vector))
- (if iep
- (make-array length :element-type '(mod 2)
- :initial-element initial-element)
- (make-array length :element-type '(mod 2))))
((csubtypep type (specifier-type 'vector))
(if (typep type 'array-type)
- (let ((etype (type-specifier
- (array-type-specialized-element-type type)))
- (vlen (car (array-type-dimensions type))))
- (if (and (numberp vlen) (/= vlen length))
- (error 'simple-type-error
- ;; These two are under-specified by ANSI.
- :datum (type-specifier type)
- :expected-type (type-specifier type)
- :format-control
- "The length of ~S does not match the specified ~
- length=~S."
- :format-arguments
- (list (type-specifier type) length)))
- (if iep
- (make-array length :element-type etype
- :initial-element initial-element)
- (make-array length :element-type etype)))
- (make-array length :initial-element initial-element)))
- (t (error 'simple-type-error
- :datum type
- :expected-type 'sequence
- :format-control "~S is a bad type specifier for sequences."
- :format-arguments (list type))))))
+ ;; KLUDGE: the above test essentially asks "Do we know
+ ;; what the upgraded-array-element-type is?" [consider
+ ;; (OR STRING BIT-VECTOR)]
+ (progn
+ (aver (= (length (array-type-dimensions type)) 1))
+ (let ((etype (type-specifier
+ (array-type-specialized-element-type type)))
+ (type-length (car (array-type-dimensions type))))
+ (unless (or (eq type-length '*)
+ (= type-length length))
+ (error 'simple-type-error
+ :datum length
+ :expected-type `(eql ,type-length)
+ :format-control "The length requested (~S) ~
+ does not match the length type restriction in ~S."
+ :format-arguments (list length
+ (type-specifier type))))
+ ;; FIXME: These calls to MAKE-ARRAY can't be
+ ;; open-coded, as the :ELEMENT-TYPE argument isn't
+ ;; constant. Probably we ought to write a
+ ;; DEFTRANSFORM for MAKE-SEQUENCE. -- CSR,
+ ;; 2002-07-22
+ (if iep
+ (make-array length :element-type etype
+ :initial-element initial-element)
+ (make-array length :element-type etype))))
+ ;; We have a subtype of VECTOR, but it isn't an array
+ ;; type. Maybe this should be a BUG instead?
+ (error 'simple-type-error
+ :datum type
+ :expected-type 'sequence
+ :format-control "~S is too hairy for MAKE-SEQUENCE."
+ :format-arguments (list (type-specifier type)))))
+ (t (bad-sequence-type-error (type-specifier type))))))
\f
;;;; SUBSEQ
;;;;
(eval-when (:compile-toplevel :execute)
-(sb!xc:defmacro vector-copy-seq (sequence type)
+(sb!xc:defmacro vector-copy-seq (sequence)
`(let ((length (length (the vector ,sequence))))
(declare (fixnum length))
(do ((index 0 (1+ index))
- (copy (make-sequence-of-type ,type length)))
+ (copy (make-sequence-like ,sequence length)))
((= index length) copy)
(declare (fixnum index))
(setf (aref copy index) (aref ,sequence index)))))
(defun vector-copy-seq* (sequence)
(declare (type vector sequence))
- (vector-copy-seq sequence
- (typecase sequence
- ;; Pick off the common cases so that we don't have to...
- ((vector t) 'simple-vector)
- (string 'simple-string)
- (bit-vector 'simple-bit-vector)
- ((vector single-float) '(simple-array single-float 1))
- ((vector double-float) '(simple-array double-float 1))
- ;; ...do a full call to TYPE-OF.
- (t (type-of sequence)))))
+ (vector-copy-seq sequence))
\f
;;;; FILL
(declare (fixnum length))
(do ((forward-index 0 (1+ forward-index))
(backward-index (1- length) (1- backward-index))
- (new-sequence (make-sequence-of-type ,type length)))
+ (new-sequence (make-sequence ,type length)))
((= forward-index length) new-sequence)
(declare (fixnum forward-index backward-index))
(setf (aref new-sequence forward-index)
(do ((sequences ,sequences (cdr sequences))
(lengths lengths (cdr lengths))
(index 0)
- (result (make-sequence-of-type ,output-type-spec total-length)))
+ (result (make-sequence ,output-type-spec total-length)))
((= index total-length) result)
(declare (fixnum index))
(let ((sequence (car sequences)))
) ; EVAL-WHEN
\f
-;;; FIXME: Make a compiler macro or transform for this which efficiently
-;;; handles the case of constant 'STRING first argument. (It's not just time
-;;; efficiency, but space efficiency..)
(defun concatenate (output-type-spec &rest sequences)
#!+sb-doc
"Return a new sequence of all the argument sequences concatenated together
which shares no structure with the original argument sequences of the
specified OUTPUT-TYPE-SPEC."
- (case (type-specifier-atom output-type-spec)
- ((simple-vector simple-string vector string array simple-array
- bit-vector simple-bit-vector base-string
- simple-base-string) ; FIXME: unifying principle here?
- (let ((result (apply #'concat-to-simple* output-type-spec sequences)))
- #!+high-security (aver (typep result output-type-spec))
- result))
- (list (apply #'concat-to-list* sequences))
+ (let ((type (specifier-type output-type-spec)))
+ (cond
+ ((csubtypep type (specifier-type 'vector))
+ (apply #'concat-to-simple* output-type-spec sequences))
+ ((csubtypep type (specifier-type 'list))
+ (apply #'concat-to-list* sequences))
(t
- (apply #'concatenate (result-type-or-lose output-type-spec) sequences))))
+ (bad-sequence-type-error output-type-spec)))))
;;; internal frobs
;;; FIXME: These are weird. They're never called anywhere except in
(declare (type index counter))))))
(declare (type index min-len))
(with-map-state sequences
- (let ((result (make-sequence-of-type output-type-spec min-len))
+ (let ((result (make-sequence output-type-spec min-len))
(index 0))
(declare (type index index))
(loop with updated-map-apply-args
;;; length of the output sequence matches any length specified
;;; in RESULT-TYPE.
(defun %map (result-type function first-sequence &rest more-sequences)
- (let ((really-fun (%coerce-callable-to-fun function)))
+ (let ((really-fun (%coerce-callable-to-fun function))
+ (type (specifier-type result-type)))
;; Handle one-argument MAP NIL specially, using ETYPECASE to turn
;; it into something which can be DEFTRANSFORMed away. (It's
;; fairly important to handle this case efficiently, since
;; approach, consing O(N-ARGS) temporary storage (which can have
;; DYNAMIC-EXTENT), then using O(N-ARGS * RESULT-LENGTH) time.
(let ((sequences (cons first-sequence more-sequences)))
- (case (type-specifier-atom result-type)
- ((nil) (%map-for-effect really-fun sequences))
- (list (%map-to-list really-fun sequences))
- ((simple-vector simple-string vector string array simple-array
- bit-vector simple-bit-vector base-string simple-base-string)
+ (cond
+ ((eq type *empty-type*) (%map-for-effect really-fun sequences))
+ ((csubtypep type (specifier-type 'list))
+ (%map-to-list really-fun sequences))
+ ((csubtypep type (specifier-type 'vector))
(%map-to-vector result-type really-fun sequences))
(t
- (apply #'map
- (result-type-or-lose result-type t)
- really-fun
- sequences)))))))
+ (bad-sequence-type-error result-type)))))))
(defun map (result-type function first-sequence &rest more-sequences)
- (sequence-of-checked-length-given-type (apply #'%map
- result-type
- function
- first-sequence
- more-sequences)
- ;; (The RESULT-TYPE isn't
- ;; strictly the type of the
- ;; result, because when
- ;; RESULT-TYPE=NIL, the result
- ;; actually has NULL type. But
- ;; that special case doesn't
- ;; matter here, since we only
- ;; look closely at vector
- ;; types; so we can just pass
- ;; RESULT-TYPE straight through
- ;; as a type specifier.)
- result-type))
+ (apply #'%map
+ result-type
+ function
+ first-sequence
+ more-sequences))
;;; KLUDGE: MAP has been rewritten substantially since the fork from
;;; CMU CL in order to give reasonable performance, but this
#!+sb-show (defvar */show* t)
(defun cannot-/show (string)
+ (declare (type simple-string string))
#+sb-xc-host (error "can't /SHOW: ~A" string)
;; We end up in this situation when we execute /SHOW too early in
;; cold init. That happens to me often enough that it's really
;; annoying for it to cause a hard failure -- which at that point is
;; hard to recover from -- instead of just diagnostic output.
- #-sb-xc-host (sb!sys:%primitive
- print
- (concatenate 'string "/can't /SHOW: " string))
+ ;;
+ ;; FIXME: The following is what we'd like to have. However,
+ ;; including it as is causes compilation of make-host-2 to fail,
+ ;; with "caught WARNING: defining setf macro for AREF when (SETF
+ ;; AREF) was previously treated as a function" during compilation of
+ ;; defsetfs.lisp
+ ;;
+ ;; #-sb-xc-host (sb!sys:%primitive print
+ ;; (concatenate 'simple-string "/can't /SHOW:" string))
+ ;;
+ ;; because the CONCATENATE is transformed to an expression involving
+ ;; (SETF AREF). Not declaring the argument as a SIMPLE-STRING (or
+ ;; otherwise inhibiting the transform; e.g. with (SAFETY 3)) would
+ ;; help, but full calls to CONCATENATE don't work this early in
+ ;; cold-init, because they now need the full assistance of the type
+ ;; system. So (KLUDGE):
+ #-sb-xc-host (sb!sys:%primitive print "/can't /SHOW:")
+ #-sb-xc-host (sb!sys:%primitive print string)
(values))
;;; Should /SHOW output be suppressed at this point?
(vector-2 (coerce sequence2 'vector))
(length-1 (length vector-1))
(length-2 (length vector-2))
- (result (make-sequence-of-type result-type
- (+ length-1 length-2))))
+ (result (make-sequence result-type
+ (+ length-1 length-2))))
(declare (vector vector-1 vector-2)
(fixnum length-1 length-2))
;; is FOLDABLE at all. Check this.
(movable #-sb-xc-host foldable)
:derive-type (result-type-specifier-nth-arg 2))
-(defknown list-to-simple-string* (list) simple-string)
-(defknown list-to-bit-vector* (list) bit-vector)
(defknown list-to-vector* (list type-specifier) vector)
-(defknown list-to-simple-vector* (list) simple-vector)
(defknown vector-to-vector* (vector type-specifier) vector)
-(defknown vector-to-simple-string* (vector) vector)
(defknown type-of (t) t (foldable flushable))
;;; %CONCATENATE (with a DEFTRANSFORM to translate constant RTYPE to
;;; CTYPE before calling %CONCATENATE) which is comparably efficient,
;;; at least once DYNAMIC-EXTENT works.
-#+nil ; FIXME: currently commented out because of bug 188
+;;;
+;;; FIXME: currently KLUDGEed because of bug 188
(deftransform concatenate ((rtype &rest sequences)
(t &rest simple-string)
- simple-string)
+ simple-string
+ :policy (< safety 3))
(collect ((lets)
(forms)
(all-lengths)
(forms `(bit-bash-copy ,n-seq ,vector-data-bit-offset
res start
,n-length))
- (forms `(setq start (+ start ,n-length)))))
+ (forms `(setq start (opaque-identity (+ start ,n-length))))))
`(lambda (rtype ,@(args))
(declare (ignore rtype))
- (let* (,@(lets)
- (res (make-string (truncate (the index (+ ,@(all-lengths)))
- sb!vm:n-byte-bits)))
- (start ,vector-data-bit-offset))
- (declare (type index start ,@(all-lengths)))
- ,@(forms)
- res))))
+ ;; KLUDGE
+ (flet ((opaque-identity (x) x))
+ (declare (notinline opaque-identity))
+ (let* (,@(lets)
+ (res (make-string (truncate (the index (+ ,@(all-lengths)))
+ sb!vm:n-byte-bits)))
+ (start ,vector-data-bit-offset))
+ (declare (type index start ,@(all-lengths)))
+ ,@(forms)
+ res)))))
\f
;;;; CONS accessor DERIVE-TYPE optimizers
\f
;;;; coercion
-(deftransform coerce ((x type) (* *) *)
+(deftransform coerce ((x type) (* *) * :node node)
(unless (constant-continuation-p type)
(give-up-ir1-transform))
(let ((tspec (ir1-transform-specifier-type (continuation-value type))))
;; FIXME: #!+long-float (t ,(error "LONG-FLOAT case needed"))
((csubtypep tspec (specifier-type 'float))
'(%single-float x))
- ((csubtypep tspec (specifier-type 'simple-vector))
- '(coerce-to-simple-vector x))
+ ((and (csubtypep tspec (specifier-type 'simple-vector))
+ (policy node (< safety 3)))
+ `(if (simple-vector-p x)
+ x
+ (replace (make-array (length x)) x)))
+ ;; FIXME: other VECTOR types?
(t
(give-up-ir1-transform)))))))
;;; BUG 186, fixed in sbcl-0.7.5.5
(assert (null (ignore-errors (test-fill-typecheck 4097))))
+;;; MAKE-SEQUENCE, COERCE, CONCATENATE, MERGE, MAP and requested
+;;; result type (BUGs 46a, 46b, 66)
+(macrolet ((assert-type-error (form)
+ `(assert (typep (nth-value 1 (ignore-errors ,form))
+ 'type-error))))
+ (dolist (type-stub '((simple-vector)
+ (vector *)
+ (vector (signed-byte 8))
+ (vector (unsigned-byte 16))
+ (vector (signed-byte 32))
+ (simple-bit-vector)))
+ (declare (optimize safety))
+ (format t "~&~S~%" type-stub)
+ ;; MAKE-SEQUENCE
+ (assert (= (length (make-sequence `(,@type-stub) 10)) 10))
+ (assert (= (length (make-sequence `(,@type-stub 10) 10)) 10))
+ (assert-type-error (make-sequence `(,@type-stub 10) 11))
+ ;; COERCE
+ (assert (= (length (coerce '(0 0 0) `(,@type-stub))) 3))
+ (assert (= (length (coerce #(0 0 0) `(,@type-stub 3))) 3))
+ (assert-type-error (coerce #*111 `(,@type-stub 4)))
+ ;; CONCATENATE
+ (assert (= (length (concatenate `(,@type-stub) #(0 0 0) #*111)) 6))
+ (assert (equalp (concatenate `(,@type-stub) #(0 0 0) #*111)
+ (coerce #(0 0 0 1 1 1) `(,@type-stub))))
+ (assert (= (length (concatenate `(,@type-stub 6) #(0 0 0) #*111)) 6))
+ (assert (equalp (concatenate `(,@type-stub 6) #(0 0 0) #*111)
+ (coerce #(0 0 0 1 1 1) `(,@type-stub 6))))
+ (assert-type-error (concatenate `(,@type-stub 5) #(0 0 0) #*111))
+ ;; MERGE
+ (assert (= (length (merge `(,@type-stub) #(0 1 0) #*111 #'>)) 6))
+ (assert (equalp (merge `(,@type-stub) #(0 1 0) #*111 #'>)
+ (coerce #(1 1 1 0 1 0) `(,@type-stub))))
+ (assert (= (length (merge `(,@type-stub 6) #(0 1 0) #*111 #'>)) 6))
+ (assert (equalp (merge `(,@type-stub 6) #(0 1 0) #*111 #'>)
+ (coerce #(1 1 1 0 1 0) `(,@type-stub 6))))
+ (assert-type-error (merge `(,@type-stub 4) #(0 1 0) #*111 #'>))
+ ;; MAP
+ (assert (= (length (map `(,@type-stub) #'logxor #(0 0 1 1) '(0 1 0 1))) 4))
+ (assert (equalp (map `(,@type-stub) #'logxor #(0 0 1 1) '(0 1 0 1))
+ (coerce #(0 1 1 0) `(,@type-stub))))
+ (assert (= (length (map `(,@type-stub 4) #'logxor #(0 0 1 1) '(0 1 0 1)))
+ 4))
+ (assert (equalp (map `(,@type-stub 4) #'logxor #(0 0 1 1) '(0 1 0 1))
+ (coerce #(0 1 1 0) `(,@type-stub 4))))
+ (assert-type-error (map `(,@type-stub 5) #'logxor #(0 0 1 1) '(0 1 0 1))))
+ ;; some more CONCATENATE tests for strings
+ (locally
+ (declare (optimize safety))
+ (assert (string= (concatenate 'string "foo" " " "bar") "foo bar"))
+ (assert (string= (concatenate '(string 7) "foo" " " "bar") "foo bar"))
+ (assert-type-error (concatenate '(string 6) "foo" " " "bar"))
+ (assert (string= (concatenate '(string 6) "foo" #(#\b #\a #\r)) "foobar"))
+ (assert-type-error (concatenate '(string 7) "foo" #(#\b #\a #\r)))))
+\f
;;; success
(quit :unix-status 104)
;;; internal versions off the main CVS branch, it gets hairier, e.g.
;;; "0.pre7.14.flaky4.13".)
-"0.7.8.7"
+"0.7.8.8"