~ chicken-core (chicken-5) /tests/scrutiny-tests.scm
Trap1;;;; scrutiny-tests.scm23(define (a)4 (define (b)5 (define (c)6 (let ((x (+ 3 4)))7 (if x 1 2))))) ; expected boolean but got number in conditional89(define (b)10 (let ((x #t))11 (if x 1 2))) ; #t is always true1213(define (foo x)14 (if x ; branches return differing number of results15 (values 1 2)16 (values 1 2 (+ (+ (+ (+ 3)))))))1718(let ((bar +))19 (bar 3 'a)) ; expected number, got symbol2021(string?) ; expected 1 argument, got 02223(print (values 1 2)) ; expected 1 result, got 224(print (values)) ; expected 1 result, got 02526(let ((x 100))27 (x)) ; expected procedure, got fixnum2829(print (+ 'a 'b)) ; expected 2 numbers, but got symbols3031(set! car 33) ; 33 does not match type of car3233((values 1 2)) ; expected procedure, got fixnum (canonicalizes to 1 result)3435; this should *not* signal a warning:36(define (test-values x)37 (define (fail) (error "failed"))38 (if x39 (values 42 43)40 (fail)))4142; same case, but nested43(define (test-values2 x y)44 (define (fail) (error "failed"))45 (if x46 (values 42 43)47 (if y (values 99 100) (fail))))4849(define (foo)50 (define (bar) (if foo 1)) ; should not warn (local)51 (for-each void '(1 2 3)) ; should not warn (self-call)52 (if foo 2) ; not in tail position53 (if bar 3)) ; should warn5455;; noreturn conditional branch enforces "number" on x56(define (foo2 x)57 (if (string? x) (error "foo") (+ x 3))58 (string-append x "abc"))5960;; implicit declaration of foo361(declare (hide foo3))6263(define (foo3 x)64 (string-append x "abc"))6566(foo3 99)6768;; predicate69(define (foo4 x)70 (if (string? x)71 (+ x 1)72 (+ x 2))) ; ok7374;; enforcement75(define (foo5 x)76 (string-append x "abc")77 (+ x 3))7879;; aliasing80(define (foo6 x)81 (let ((y x))82 (string-append x "abc")83 (+ x 3))) ;XXX (+ y 3) does not work yet8485;; user-defined predicate86(: foo7 (* -> boolean : string))87(define (foo7 x) (string? x))8889(when (foo7 x)90 (+ x 1)) ; will warn about "x" being a string9192;; declared procedure types are enforcing93(define-type s2s (string -> symbol))9495(: foo8 s2s)96(define (foo8 x) (string->symbol x))97(: foo9 s2s)98(declare (enforce-argument-types foo9))99(define (foo9 x) (string->symbol x))100101(define (foo10 x)102 (foo8 x)103 (+ x 1) ; foo8 does not enforce x (no warning)104 (foo9 x) ; + enforces number on x105 (+ x 1)) ; foo9 does enforce106107;; trigger warnings for incompatible types in "the" forms108(define (foo10 x)109 (string-append (the pair (substring x 0 10))) ; 1110 (the * (values 1 2)) ; 1 + 2111 (the * (values)) ; 3112 (the fixnum (* x y))) ; nothing (but warns about "x" being string)113114115;; Reported by Joerg Wittenberger:116;117; - assignment inside first conditional does not invalidate blist118;; entries for "ins"/"del" in outer flow.119120(define (write-blob-to-sql sql identifier last blob c-c)121 (define ins '())122 (define del '())123 (if (vector? blob)124 (begin125 (set! ins (vector-ref blob 1))126 (set! del (vector-ref blob 2))127 (set! blob (vector-ref blob 0))))128 (if (or (pair? ins)129 (pair? del))130 (<handle-ins-and-del>))131 (<do-some-more>))132133;; Checking whether reported line numbers inside modules are correct134(module foo (blabla)135 (import scheme)136 (define (blabla)137 (+ 1 'x)))138139;; Reported by megane in #884:140;;141;; Custom types defined in modules need to be resolved during canonicalization142(module bar ()143 (import scheme chicken.type)144 (define-type footype string)145 (the footype "bar"))146147;; Record type tags with module namespaces should not warn (#1513)148(module foo *149 (import (scheme) (chicken base) (chicken type))150 (: make-foo (string --> (struct foo)))151 (define-record foo bar))152153(: deprecated-procedure deprecated)154(define (deprecated-procedure x) (+ x x))155(deprecated-procedure 1)156157(: another-deprecated-procedure (deprecated replacement-procedure))158(define (another-deprecated-procedure x) (+ x x))159(another-deprecated-procedure 2)160161;; Needed to use "over-all-instantiations" or matching "vector"/"list" type162;; with "vector-of"/"list-of" type (reported by megane)163(: apply1 (forall (a b) (procedure ((procedure (#!rest a) b) (list-of a)) b)))164165(define (apply1 f args)166 (apply f args))167168(apply1 + (list 'a 2 3)) ; <- no type warning (#948)169(apply1 + (cons 'a (cons 2 (cons 3 '())))) ; <- same here (#952)170171;; multiple-value return syntax172(: mv (-> . *))173(: mv (procedure () . *))174175;; procedures from the type environment should still enforce, etc.176(let ((x (the (or fixnum string) _))177 (f (the (forall (a)178 (a -> (-> a)))179 (lambda (a)180 (lambda () a)))))181 (((f +)) x) ; (or fixnum string) -> fixnum182 (fixnum? x)) ; should report183184;; typeset reduction185186(: char-or-string? (* -> boolean : (or char string)))187188(let ((x _))189 (if (char-or-string? x)190 (symbol? x) ; should report with x = (or char string)191 (string? x))) ; should report with x = (not (or char string))192193(let ((x (the fixnum _)))194 (if (char-or-string? x)195 (symbol? x) ; should report with x = (or char string)196 (string? x))) ; should report with x = fixnum197198(let ((x (the (or char symbol) _)))199 (if (char-or-string? x)200 (symbol? x) ; should report with x = char201 (string? x))) ; should report with x = symbol202203(let ((x (the (or char symbol string) _)))204 (if (char-or-string? x)205 (symbol? x) ; should report with x = (or char string)206 (string? x))) ; should report with x = symbol207208;; list- and pair-type argument matching209210(let ((f (the (pair -> *) _))) (f (list))) ; warning211(let ((f (the (pair -> *) _))) (f (make-list x))) ; no warning212(let ((f (the (null -> *) _))) (f (list 1))) ; warning213(let ((f (the (null -> *) _))) (f (make-list x))) ; no warning214(let ((f (the (list -> *) _))) (f (cons 1 2))) ; warning215(let ((f (the (list -> *) _))) (f (cons 1 x))) ; no warning216217218;; Indexing into vectors or lists of known size.219(let ((v1 (vector 'a 'b 'c)))220 (define (vector-ref-warn1) (vector-ref v1 -1))221 ;; After the first expression, v1's type is smashed to (vector * * *)!222 (define (vector-ref-warn2) (vector-ref v1 3))223 (define (vector-ref-warn3) (vector-ref v1 4))224 (define (vector-ref-nowarn1) (vector-ref v1 0))225 (define (vector-ref-nowarn2) (vector-ref v1 2))226 (define (vector-ref-standard-warn1) (vector-ref v1 'bad))227 (define (vector-set!-warn1) (vector-set! v1 -1 'whatever))228 (define (vector-set!-warn2) (vector-set! v1 3 'whatever))229 (define (vector-set!-warn3) (vector-set! v1 4 'whatever))230 (define (vector-set!-nowarn1) (vector-set! v1 0 'whatever))231 (define (vector-set!-nowarn2) (vector-set! v1 2 'whatever))232 (define (vector-set!-standard-warn1) (vector-set! v1 'bad 'whatever)))233234;; The specific list type will be smashed to just "(or pair null)"235;; after the first operation. This is why the let is repeated;236;; otherwise we won't get the warnings for subsequent references.237(let ((l1 (list 'a 'b 'c)))238 (define (list-ref-warn1) (list-ref l1 -1)))239;; This warns regardless of not knowing the length of the list240(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))241 (define (list-ref-warn2) (list-ref l2 -1)))242;; Not knowing the length of a "list-of" is not an issue here243(let ((l3 (the (list-of symbol) '(x y z))))244 (define (list-ref-warn3) (list-ref l3 -1)))245(let ((l1 (list 'a 'b 'c)))246 (define (list-ref-warn4) (list-ref l1 3)))247;; This can't warn: it strictly doesn't know the length of the list.248;; The eval could return a list of length >= 1!249#;(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))250 (define (list-ref-warn5) (list-ref l2 3)))251(let ((l1 (list 'a 'b 'c)))252 (define (list-ref-warn5) (list-ref l1 4)))253;; Same as above254#;(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))255 (define (list-ref-warn6) (list-ref l2 4)))256257;; We add the second check to ensure that we don't give false warnings258;; for smashed types, because we don't know the original size.259(let ((l1 (list 'a 'b 'c)))260 (define (list-ref-nowarn1) (list-ref l1 0))261 (define (list-ref-nowarn2) (list-ref l1 0)))262(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))263 (define (list-ref-nowarn3) (list-ref l2 0))264 (define (list-ref-nowarn4) (list-ref l2 0)))265(let ((l1 (list 'a 'b 'c)))266 (define (list-ref-nowarn5) (list-ref l1 2))267 (define (list-ref-nowarn6) (list-ref l1 2)))268(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))269 (define (list-ref-nowarn7) (list-ref l2 2))270 (define (list-ref-nowarn8) (list-ref l2 2)))271;; Verify that we don't give bogus warnings, like mentioned above.272(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))273 (define (list-ref-nowarn9) (list-ref l2 5)))274;; We don't know the length of a "list-of", so we can't warn275(let ((l3 (the (list-of symbol) '(x y z))))276 (define (list-ref-nowarn10) (list-ref l3 100)))277278;; The second check here should still give a warning, this has279;; nothing to do with component smashing.280(let ((l1 (list 'a 'b 'c)))281 (define (list-ref-standard-warn1) (list-ref l1 'bad))282 (define (list-ref-standard-warn2) (list-ref l1 'bad)))283(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))284 (define (list-ref-standard-warn3) (list-ref l2 'bad))285 (define (list-ref-standard-warn4) (list-ref l2 'bad)))286287;; Test type preservation of list-ref288(let ((l1 (list 'a 'b 'c)))289 (define (list-ref-type-warn1) (add1 (list-ref l1 1))))290(let ((l2 (cons 'a (cons 'b (cons 'c (eval '(list)))))))291 (define (list-ref-type-warn2) (add1 (list-ref l2 1))))292;; This is handled by the list-ref entry in types.db, *not* the293;; special-cased code.294(let ((l3 (the (list-of symbol) '(a b c))))295 (define (list-ref-type-warn3) (add1 (list-ref l3 1))))296297;; Sanity check298(let ((l1 (list 1 2 3)))299 (define (list-ref-type-nowarn1) (add1 (list-ref l1 1))))300(let ((l2 (cons 1 (cons 2 (cons 3 (eval '(list)))))))301 (define (list-ref-type-nowarn2) (add1 (list-ref l2 1))))302(let ((l3 (the (list-of fixnum) '(1 2 3))))303 (define (list-ref-type-nowarn3) (add1 (list-ref l3 1))))304305;; Test type preservation of append (TODO: decouple from list-ref)306(let ((l1 (append (list 'x 'y) (list 1 2 (eval '(list))))))307 (define (append-result-type-warn1) (add1 (list-ref l1 1))))308;; This currently doesn't warn because pair types aren't joined yet309#;(let ((l2 (append (cons 'x (cons 'y (eval '(list)))) (list 'x 'y))))310 (define (append-result-type-warn2) (add1 (list-ref l2 1))))311(let ((l3 (append (the (list-of symbol) '(x y)) '(a b))))312 (define (append-result-type-warn2) (add1 (list-ref l3 3))))313314(let ((l1 (append (list 1 2) (list 'x 'y (eval '(list))))))315 (define (append-result-type-nowarn1) (add1 (list-ref l1 1))))316(let ((l2 (append (cons 1 (cons 2 (eval '(list)))) (list 'x))))317 (define (append-result-type-nowarn2) (add1 (list-ref l2 1))))318(let ((l3 (append (the (list-of fixnum) '(1 2)) '(x y))))319 (define (append-result-type-nowarn3) (add1 (list-ref l3 1))))320321;; Check the trail is restored from the combined typeenv322(compiler-typecase (list 2 'a)323 ((forall (x) (list x x)) 1)324 (else #t))