;;;; predicates so complex that the only reasonable implentation is
;;;; via function call.
;;;;
-;;;; Some standard types (such as SEQUENCE) are best tested by letting
-;;;; the TYPEP source transform do its thing with the expansion. These
+;;;; Some standard types (such as ATOM) are best tested by letting the
+;;;; TYPEP source transform do its thing with the expansion. These
;;;; types (and corresponding predicates) are not maintained in this
;;;; association. In this case, there need not be any predicate
;;;; function unless it is required by the Common Lisp specification.
;;; constant. At worst, it will convert to %TYPEP, which will prevent
;;; spurious attempts at transformation (and possible repeated
;;; warnings.)
-(deftransform typep ((object type))
+(deftransform typep ((object type) * * :node node)
(unless (constant-lvar-p type)
(give-up-ir1-transform "can't open-code test of non-constant type"))
- `(typep object ',(lvar-value type)))
+ (multiple-value-bind (expansion fail-p)
+ (source-transform-typep 'object (lvar-value type))
+ (if fail-p
+ (abort-ir1-transform)
+ expansion)))
;;; If the lvar OBJECT definitely is or isn't of the specified
;;; type, then return T or NIL as appropriate. Otherwise quietly
(aver ctype)
(ir1-transform-type-predicate object ctype)))
-;;; If FIND-CLASS is called on a constant class, locate the CLASS-CELL
-;;; at load time.
+;;; If FIND-CLASSOID is called on a constant class, locate the
+;;; CLASSOID-CELL at load time.
(deftransform find-classoid ((name) ((constant-arg symbol)) *)
(let* ((name (lvar-value name))
- (cell (find-classoid-cell name)))
+ (cell (find-classoid-cell name :create t)))
`(or (classoid-cell-classoid ',cell)
(error "class not yet defined: ~S" name))))
\f
(define-type-predicate numberp number)
(define-type-predicate rationalp rational)
(define-type-predicate realp real)
+ (define-type-predicate sequencep sequence)
+ (define-type-predicate extended-sequence-p extended-sequence)
(define-type-predicate simple-bit-vector-p simple-bit-vector)
(define-type-predicate simple-string-p simple-string)
(define-type-predicate simple-vector-p simple-vector)
class:~% ~S"
class))
(t
- ;; Delay the type transform to give type propagation a chance.
- (delay-ir1-transform node :constraint)
+ ;; Delay the type transform to give type propagation a chance.
+ (delay-ir1-transform node :constraint)
;; Otherwise transform the type test.
(multiple-value-bind (pred get-layout)
`((when (layout-invalid ,n-layout)
(%layout-invalid-error object ',layout))))
(eq ,n-layout ',layout)))))
- ((and (typep class 'basic-structure-classoid) layout)
+ ((and (typep class 'structure-classoid) layout)
;; structure type tests; hierarchical layout depths
(let ((depthoid (layout-depthoid layout))
(n-layout (gensym)))
`(and (,pred object)
(let ((,n-layout (,get-layout object)))
- ,@(when (policy *lexenv* (>= safety speed))
- `((when (layout-invalid ,n-layout)
- (%layout-invalid-error object ',layout))))
+ ;; we used to check for invalid layouts here,
+ ;; but in fact that's both unnecessary and
+ ;; wrong; it's unnecessary because structure
+ ;; classes can't be redefined, and it's wrong
+ ;; because it is quite legitimate to pass an
+ ;; object with an invalid layout to a structure
+ ;; type test.
(if (eq ,n-layout ',layout)
t
(and (> (layout-depthoid ,n-layout)
,depthoid)
(locally (declare (optimize (safety 0)))
- (eq (svref (layout-inherits ,n-layout)
- ,depthoid)
+ ;; Use DATA-VECTOR-REF directly,
+ ;; since that's what SVREF in a
+ ;; SAFETY 0 lexenv will eventually be
+ ;; transformed to. This can give a
+ ;; large compilation speedup, since
+ ;; %INSTANCE-TYPEPs are frequently
+ ;; created during GENERATE-TYPE-CHECKS,
+ ;; and the normal aref transformation path
+ ;; is pretty heavy.
+ (eq (data-vector-ref (layout-inherits ,n-layout)
+ ,depthoid)
',layout))))))))
((and layout (>= (layout-depthoid layout) 0))
;; hierarchical layout depths for other things (e.g.
- ;; CONDITIONs)
+ ;; CONDITION, STREAM)
(let ((depthoid (layout-depthoid layout))
(n-layout (gensym))
(n-inherits (gensym)))
`(and (,pred object)
(let ((,n-layout (,get-layout object)))
- ,@(when (policy *lexenv* (>= safety speed))
- `((when (layout-invalid ,n-layout)
- (%layout-invalid-error object ',layout))))
+ (when (layout-invalid ,n-layout)
+ (setq ,n-layout (update-object-layout-or-invalid
+ object ',layout)))
(if (eq ,n-layout ',layout)
t
(let ((,n-inherits (layout-inherits ,n-layout)))
(declare (optimize (safety 0)))
(and (> (length ,n-inherits) ,depthoid)
- (eq (svref ,n-inherits ,depthoid)
+ ;; See above.
+ (eq (data-vector-ref ,n-inherits ,depthoid)
',layout))))))))
(t
(/noshow "default case -- ,PRED and CLASS-CELL-TYPEP")
`(and (,pred object)
(classoid-cell-typep (,get-layout object)
- ',(find-classoid-cell name)
+ ',(find-classoid-cell name :create t)
object)))))))))
;;; If the specifier argument is a quoted constant, then we consider
;;; to that predicate. Otherwise, we dispatch off of the type's type.
;;; These transformations can increase space, but it is hard to tell
;;; when, so we ignore policy and always do them.
+(defun source-transform-typep (object type)
+ (let ((ctype (careful-specifier-type type)))
+ (or (when (not ctype)
+ (compiler-warn "illegal type specifier for TYPEP: ~S" type)
+ (return-from source-transform-typep (values nil t)))
+ (let ((pred (cdr (assoc ctype *backend-type-predicates*
+ :test #'type=))))
+ (when pred `(,pred ,object)))
+ (typecase ctype
+ (hairy-type
+ (source-transform-hairy-typep object ctype))
+ (negation-type
+ (source-transform-negation-typep object ctype))
+ (union-type
+ (source-transform-union-typep object ctype))
+ (intersection-type
+ (source-transform-intersection-typep object ctype))
+ (member-type
+ `(if (member ,object ',(member-type-members ctype)) t))
+ (args-type
+ (compiler-warn "illegal type specifier for TYPEP: ~S" type)
+ (return-from source-transform-typep (values nil t)))
+ (t nil))
+ (typecase ctype
+ (numeric-type
+ (source-transform-numeric-typep object ctype))
+ (classoid
+ `(%instance-typep ,object ',type))
+ (array-type
+ (source-transform-array-typep object ctype))
+ (cons-type
+ (source-transform-cons-typep object ctype))
+ (character-set-type
+ (source-transform-character-set-typep object ctype))
+ (t nil))
+ `(%typep ,object ',type))))
+
(define-source-transform typep (object spec)
;; KLUDGE: It looks bad to only do this on explicitly quoted forms,
;; since that would overlook other kinds of constants. But it turns
;; lvar, transforms it into a quoted form, and gives this
;; source transform another chance, so it all works out OK, in a
;; weird roundabout way. -- WHN 2001-03-18
- (if (and (consp spec) (eq (car spec) 'quote))
- (let ((type (careful-specifier-type (cadr spec))))
- (block bail
- (or (when (not type)
- (compiler-warn "illegal type specifier for TYPEP: ~S"
- (cadr spec))
- (return-from bail (values nil t)))
- (let ((pred (cdr (assoc type *backend-type-predicates*
- :test #'type=))))
- (when pred `(,pred ,object)))
- (typecase type
- (hairy-type
- (source-transform-hairy-typep object type))
- (negation-type
- (source-transform-negation-typep object type))
- (union-type
- (source-transform-union-typep object type))
- (intersection-type
- (source-transform-intersection-typep object type))
- (member-type
- `(if (member ,object ',(member-type-members type)) t))
- (args-type
- (compiler-warn "illegal type specifier for TYPEP: ~S"
- (cadr spec))
- (return-from bail (values nil t)))
- (t nil))
- (typecase type
- (numeric-type
- (source-transform-numeric-typep object type))
- (classoid
- `(%instance-typep ,object ,spec))
- (array-type
- (source-transform-array-typep object type))
- (cons-type
- (source-transform-cons-typep object type))
- (character-set-type
- (source-transform-character-set-typep object type))
- (t nil))
- `(%typep ,object ,spec))))
+ (if (and (consp spec)
+ (eq (car spec) 'quote)
+ (or (not *allow-instrumenting*)
+ (policy *lexenv* (= store-coverage-data 0))))
+ (source-transform-typep object (cadr spec))
(values nil t)))
\f
;;;; coercion