~ chicken-core (chicken-5) 0fbbba9d5fc0dcce7b2364beaf3396d501967d0e
commit 0fbbba9d5fc0dcce7b2364beaf3396d501967d0e Author: felix <felix@call-with-current-continuation.org> AuthorDate: Mon Sep 19 13:00:52 2011 +0200 Commit: Peter Bex <peter.bex@xs4all.nl> CommitDate: Thu Sep 22 21:31:25 2011 +0200 This commit fixes several problems with the scrutinizer: - instantiations of type-variables need to be done over all alternatives in a union ("or") type - swapped order of "or"-type matching to handle cases where matching two union types failed where they shouldn't - resolution of type-variables may require type-simplification - subtype-checking uses existing typeenv machinery - commented out unused typecheck-generation code for the time being - adds a few testcase Squashed commit of the following: commit 34f451dbcc3119c0307e503a97a512eff964e5a9 Merge: 93ccf52... 60b4a6c... Author: felix <felix@call-with-current-continuation.org> Date: Mon Sep 19 13:00:15 2011 +0200 Merge branch 'scrutiny-fixes' into tmp commit 60b4a6c2f7aa7dd5afb0c0ad1436177a34d634ed Merge: 5ae00b5... e8d45b2... Author: felix <felix@call-with-current-continuation.org> Date: Mon Sep 19 12:41:27 2011 +0200 Merge branch 'felix-pending' into scrutiny-fixes commit 5ae00b5a16ea6cf0daeed8cc85d15eb15525ee7f Author: felix <felix@call-with-current-continuation.org> Date: Mon Sep 19 12:28:36 2011 +0200 specialization for atan/2 in mixed fixnum/flonum case commit 60371ba7dec19f1110e1ad79c4e4e7ac83938df2 Author: felix <felix@call-with-current-continuation.org> Date: Mon Sep 19 09:19:32 2011 +0200 specializations for expt in mixed flonum/fixnum case commit 8c2c8764362ccf540a4a01c65c71fbf5993f00ef Author: felix <felix@call-with-current-continuation.org> Date: Mon Sep 19 08:39:54 2011 +0200 correct order of OR-type matching; slight simplification of o-a-i; added testcase commit 032448a84ef067d4dc786916565efe34e26c0468 Author: felix <felix@call-with-current-continuation.org> Date: Sat Sep 17 15:16:54 2011 +0200 list-of is not a subtype of pair or fixed-length list; factored out setting up of final instantiations of vars in over-all-instantiations; fixed bugs in the latter commit b629144e1f3127f3ae664a07670542df95ea2a32 Author: felix <felix@call-with-current-continuation.org> Date: Fri Sep 16 23:52:16 2011 +0200 scrutiny not completely broken anymore, but still feels flaky commit feeec2010eaab6386a4890cf13c7691a62b96073 Author: felix <felix@call-with-current-continuation.org> Date: Fri Sep 16 23:51:38 2011 +0200 tiny fix in compile-all script commit 85dd3577a145b344db34d5037d3a841bca209304 Author: felix <felix@call-with-current-continuation.org> Date: Fri Sep 16 23:51:19 2011 +0200 removed compile-all target (slightly broken and redundant) commit 3aa6214bf4b8ef80f228bc2b1ef0eb0d9720e2e7 Author: felix <felix@call-with-current-continuation.org> Date: Fri Sep 16 18:39:53 2011 +0200 added debugging output commit 593bb9b84d622f79dc838d95f558ddad8cf108b2 Author: felix <felix@call-with-current-continuation.org> Date: Fri Sep 16 18:25:55 2011 +0200 combine typevar instantiations over all elements of 'or' types; type<=? does the same and uses usual typeenv mechanisms commit 4a06a44531806cfa8306c6076f96e33613401ebf Author: felix <felix@call-with-current-continuation.org> Date: Fri Sep 16 14:36:05 2011 +0200 trying to reduce list-type complexity, variable unification results in incorrect instantiation when multiple alternatives exist, i.e. (list-of a) = (list (or X Y)) - first match insantiates a, second is ignored, but must match, too Signed-off-by: Peter Bex <peter.bex@xs4all.nl> diff --git a/scrutinizer.scm b/scrutinizer.scm index 895481eb..61971bc4 100755 --- a/scrutinizer.scm +++ b/scrutinizer.scm @@ -31,7 +31,7 @@ noreturn-type? rest-type procedure-name d-depth noreturn-procedure-type? trail trail-restore typename multiples procedure-arguments procedure-results - smash-component-types! generate-type-checks! + smash-component-types! generate-type-checks! over-all-instantiations compatible-types? type<=? match-types resolve match-argument-types)) @@ -155,14 +155,6 @@ (cond ((variable-mark id '##compiler#type) => (lambda (a) (cond - #| XXX Disabled, since this would remove specializations in core library - code, where these get assigned. Still, it would be safer to - unmark assigned vars... - ((and (get db id 'assigned) ; remove assigned global from type db - (not (variable-mark id '##compiler#declared-type))) - (mark-variable id '##compiler#type #f) - '(*)) - |# ((eq? a 'deprecated) (report loc @@ -346,7 +338,6 @@ (when (noreturn-procedure-type? ptype) (set! noreturn #t)) (let ((r (procedure-result-types ptype values-rest (cdr args) typeenv))) - ;;XXX we should check whether this is a standard- or extended binding (let* ((pn (procedure-name ptype)) (trail0 trail)) (when pn @@ -613,7 +604,7 @@ "assignment of value of type `~a' to toplevel variable `~a' does not match declared type `~a'" rt var type) #t)) - (when (and (not type) + (when (and (not type) ;XXX global declaration could allow this (not b) (not (eq? '* rt)) (not (get db var 'unknown))) @@ -645,7 +636,7 @@ (alist-cons (cons var (car flow)) (if (or strict-variable-types - ;;XXX needs to be tested more + ;;XXX needs to be tested more but might be worth it #;(not (get db var 'captured))) rt '*) @@ -705,10 +696,6 @@ (not (get db var 'assigned)) (not oparg?)))) (cond (pred - ;;XXX we could add a blist entry for var in the other - ;; branch by subtracting pt from the current type - ;; of var, at least in the simple case of - ;; "(or ... <PT> ...)" -> "(or ... ...)" (let ((pt (resolve pt typeenv))) (d " predicate `~a' indicates `~a' is ~a in flow ~a" pn var pt (car ctags)) @@ -804,15 +791,15 @@ (let ((rn (walk (first (node-subexpressions node)) '() '() #f #f (list (tag)) #f))) (when (and (pair? specialization-statistics) - (debugging 'x "specializations:")) ;XXX + (debugging 'x "specializations:")) ;XXX use 'o (for-each (lambda (ss) (printf " ~a ~s~%" (cdr ss) (car ss))) specialization-statistics)) (when (positive? safe-calls) - (debugging 'x "safe calls" safe-calls)) ;XXX + (debugging 'x "safe calls" safe-calls)) ;XXX use 'o (when (positive? dropped-branches) - (debugging 'x "dropped branches" dropped-branches)) ;XXX + (debugging 'x "dropped branches" dropped-branches)) ;XXX use 'o rn))) @@ -963,14 +950,6 @@ (match-results (cdr results1) (cdr results2))) (else #f))) - (define (match1/restore t1 t2) - (let* ((trail0 trail) - (m (match1 t1 t2))) - (cond (m) - (else - (trail-restore trail0 typeenv) - #f)))) - (define (rawmatch1 t1 t2) (fluid-let ((exact #f) (all #f)) @@ -978,12 +957,11 @@ (define (match1 t1 t2) ;; note: the order of determining the type is important - ;;(dd " match1: ~s <-> ~s" t1 t2) + (dd " match1: ~s <-> ~s" t1 t2) (cond ((eq? t1 t2)) ;;XXX do we have to handle circularities? ((and (symbol? t1) (assq t1 typeenv)) => (lambda (e) - ;;XXX is "raw" matching for constraints correct? (cond ((second e) (and (match1 (second e) t2) (or (not (third e)) ; constraint @@ -1032,10 +1010,25 @@ (m (match1 t1 (cadr t2)))) (trail-restore trail0 typeenv) (not m)))) - ((and (pair? t1) (eq? 'or (car t1))) - (any (cut match1/restore <> t2) (cdr t1))) + ;; this is subtle: "or" types for t2 are less restrictive, + ;; so we handle them before "or" types for t1 ((and (pair? t2) (eq? 'or (car t2))) - ((if (or exact all) every any) (cut match1/restore t1 <>) (cdr t2))) + (over-all-instantiations + (cdr t2) + typeenv + (lambda (t) (match1 t1 t)) + (lambda () + (if (or exact all) + (every + (cut match1 t1 <>) + (cdr t2)) + #t)))) + ;; s.a. + ((and (pair? t1) (eq? 'or (car t1))) + (over-all-instantiations + (cdr t1) + typeenv + (lambda (t) (match1 t t2)))) ; o-a-i ensures at least one element matches ((and (pair? t1) (eq? 'forall (car t1))) (match1 (third t1) t2)) ; assumes typeenv has already been extracted ((and (pair? t2) (eq? 'forall (car t2))) @@ -1104,12 +1097,11 @@ (and (pair? t1) (case (car t1) ((list-of) - (and (not exact) + (and ;(not exact) (match1 (second t1) (second t2)) (match1 t1 (third t2)))) ((list) (and (match1 (second t1) (second t2)) - (or (not exact) (pair? (cdr t1))) (match1 (if (null? (cdr t1)) 'null `(list ,@(cddr t1))) @@ -1297,8 +1289,14 @@ (if (and (eq? '* tcar) (eq? '* tcdr)) 'pair (let rec ((tr tcdr) (ts (list tcar))) - (cond ((and (pair? tr) (eq? 'pair (first tr))) + (cond ((eq? 'null tr) + `(list-of ,(simplify `(or ,@ts)))) + ((and (pair? tr) (eq? 'pair (first tr))) (rec (third tr) (cons (second tr) ts))) + ((and (pair? tr) (eq? 'list (first tr))) + `(list-of ,(simplify `(or ,@ts ,@(cdr tr))))) + ((and (pair? tr) (eq? 'list-of (first tr))) + `(list-of ,(simplify-type `(or ,@(reverse ts) ,@(cdr tr))))) (else `(pair ,tcar ,tcdr))))))) ((vector-of) (let ((t2 (simplify (second t)))) @@ -1395,134 +1393,137 @@ (define (type<=? t1 t2) - (let ((typeenv '()) ; ((VAR1 . TYPE1) ...) - (constraints '())) ; ((VAR1 TYPE1) ...) - - (define (extract-vars tv) - (set! typeenv - (append (map (lambda (v) - (cons (if (symbol? v) v (first v)) #f)) - tv) - typeenv)) - (set! constraints - (append (filter-map - (lambda (v) - (and (pair? v) v)) - tv) - constraints))) - - (cond ((eq? t1 t2)) - ;;XXX do we need to handle circularities in typevar-references? - ((and (symbol? t1) (assq t1 typeenv)) => - (lambda (e) - (if (cdr e) - (type<=? (cdr e) t2) - (begin - (set-cdr! e t2) - (cond ((assq t1 constraints) => - (lambda (c) (type<=? (second c) t2))) - (else #t)))))) - ((and (symbol? t2) (assq t2 typeenv)) => - (lambda (e) - (if (cdr e) - (type<=? t1 (cdr e)) - (begin - (set-cdr! e t1) - (cond ((assq t2 constraints) => - (lambda (c) (type<=? t1 (second c)))) - (else #t)))))) - ((memq t2 '(* undefined))) - ((eq? 'pair t1) (type<=? '(pair * *) t2)) - ((memq t1 '(vector list)) (type<=? `(,t1 *) t2)) - ((and (eq? 'null t1) - (pair? t2) - (eq? (car t2) 'list-of))) - ((and (pair? t1) (eq? 'forall (car t1))) - (extract-vars (second t1)) - (type<=? (third t1) t2)) - ((and (pair? t2) (eq? 'forall (car t2))) - (extract-vars (second t2)) - (type<=? t1 (third t2))) - (else - (case t2 - ((procedure) (and (pair? t1) (eq? 'procedure (car t1)))) - ((number) (memq t1 '(fixnum float))) - ((vector) (type<=? t1 '(vector-of *))) - ((list) (type<=? t1 '(list-of *))) - ((pair) (type<=? t1 '(pair * *))) - (else - (cond ((not (pair? t1)) #f) - ((not (pair? t2)) #f) - ((eq? 'or (car t2)) - (every (cut type<=? t1 <>) (cdr t2))) - ((and (eq? 'vector (car t1)) (eq? 'vector-of (car t2))) - (every (cute type<=? <> (second t2)) (cdr t1))) - ((and (eq? 'vector-of (car t1)) (eq? 'vector (car t2))) - (every (cute type<=? (second t1) <>) (cdr t2))) - ((and (eq? 'list (car t1)) (eq? 'list-of (car t2))) - (every (cute type<=? <> (second t2)) (cdr t1))) - ((and (eq? 'list-of (car t1)) (eq? 'list (car t2))) - (every (cute type<=? (second t1) <>) (cdr t2))) - ((not (eq? (car t1) (car t2))) #f) + (let* ((typeenv (append-map type-typeenv (list t1 t2))) + (trail0 trail) + (r (let test ((t1 t1) (t2 t2)) + (cond ((eq? t1 t2)) + ((and (symbol? t1) (assq t1 typeenv)) => + (lambda (e) + (cond ((second e) (test (second e) t2)) + (else + (set-car! (cdr e) t2) + (or (not (third e)) + (test (third e) t2)))))) + ((and (symbol? t2) (assq t2 typeenv)) => + (lambda (e) + (cond ((second e) (test t1 (second e))) + (else + (set-cdr! e t1) + (or (not (third e)) + (test t1 (third e))))))) + ((memq t2 '(* undefined))) + ((eq? 'pair t1) (test '(pair * *) t2)) + ((memq t1 '(vector list)) (test `(,t1 *) t2)) + ((and (eq? 'null t1) + (pair? t2) + (eq? (car t2) 'list-of))) + ((and (pair? t1) (eq? 'forall (car t1))) + (test (third t1) t2)) + ((and (pair? t2) (eq? 'forall (car t2))) + (test t1 (third t2))) (else - (case (car t1) - ((or) (every (cut type<=? <> t2) (cdr t1))) - ((vector-of list-of) (type<=? (second t1) (second t2))) - ((pair) (every type<=? (cdr t1) (cdr t2))) - ((procedure) - (let ((args1 (if (named? t1) (caddr t1) (cadr t1))) - (args2 (if (named? t2) (caddr t2) (cadr t2))) - (res1 (if (named? t1) (cdddr t1) (cddr t1))) - (res2 (if (named? t2) (cdddr t2) (cddr t2))) ) - (let loop1 ((args1 args1) - (args2 args2) - (rtype1 #f) - (rtype2 #f) - (m1 0) - (m2 0)) - (cond ((null? args1) - (and (cond ((null? args2) - (if rtype1 - (if rtype2 - (type<=? rtype1 rtype2) - #f) - #t)) - ((eq? '#!optional (car args2)) - (not rtype1)) - ((eq? '#!rest (car args2)) - (or (null? (cdr args2)) - rtype1 - (type<=? rtype1 (cadr args2)))) - (else (>= m2 m1))) - (let loop2 ((res1 res1) (res2 res2)) - (cond ((eq? '* res2) #t) - ((null? res2) (null? res1)) - ((eq? '* res1) #f) - ((type<=? (car res1) (car res2)) - (loop2 (cdr res1) (cdr res2))) - (else #f))))) - ((eq? (car args1) '#!optional) - (loop1 (cdr args1) args2 #f rtype2 1 m2)) - ((eq? (car args1) '#!rest) - (if (null? (cdr args1)) - (loop1 '() args2 '* rtype2 2 m2) - (loop1 '() args2 (cadr args1) rtype2 2 m2))) - ((null? args2) - (and rtype2 - (type<=? (car args1) rtype2) - (loop1 (cdr args1) '() rtype1 rtype2 m1 m2))) - ((eq? (car args2) '#!optional) - (loop1 args1 (cdr args2) rtype1 #f m1 1)) - ((eq? (car args2) '#!rest) - (if (null? (cdr args2)) - (loop1 args1 '() rtype1 '* m1 2) - (loop1 args1 '() rtype1 (cadr args2) m1 2))) - ((type<=? - (or rtype1 (car args1)) - (or rtype2 (car args2))) - (loop1 (cdr args1) (cdr args2) rtype1 rtype2 m1 m2)) - (else #f))))) - (else #f)))))))))) + (case t2 + ((procedure) (and (pair? t1) (eq? 'procedure (car t1)))) + ((number) (memq t1 '(fixnum float))) + ((vector) (test t1 '(vector-of *))) + ((list) (test t1 '(list-of *))) + ((pair) (test t1 '(pair * *))) + (else + (cond ((not (pair? t1)) #f) + ((not (pair? t2)) #f) + ((eq? 'or (car t2)) + (over-all-instantiations + (cdr t2) + typeenv + (lambda (t) (test t1 t)) + (lambda () + (every (cut test t1 <>) (cdr t2))))) + ((and (eq? 'vector (car t1)) (eq? 'vector-of (car t2))) + (every (cute test <> (second t2)) (cdr t1))) + ((and (eq? 'vector-of (car t1)) (eq? 'vector (car t2))) + (every (cute test (second t1) <>) (cdr t2))) + ((and (eq? 'list (car t1)) (eq? 'list-of (car t2))) + (every (cute test <> (second t2)) (cdr t1))) + ((and (eq? 'list (car t1)) (eq? 'pair (car t2))) + (and (not (null? (cdr t1))) + (test (second t1) (second t2)) + (test t1 (third t2)))) + ((and (eq? 'pair (car t1)) (eq? 'list (car t2))) + (and (not (null? (cdr t2))) + (test (second t1) (second t2)) + (test (third t1) t2))) + ((and (eq? 'pair (car t1)) (eq? 'list-of (car t2))) + (and (test (second t1) (second t2)) + (test (third t1) t2))) + ((not (eq? (car t1) (car t2))) #f) + (else + (case (car t1) + ((or) + (over-all-instantiations + (cdr t1) + typeenv + (lambda (t) (test t t2)) + (lambda () + (every (cut test <> t2) (cdr t1))))) + ((vector-of list-of) (test (second t1) (second t2))) + ((pair) (every test (cdr t1) (cdr t2))) + ((procedure) + (let ((args1 (if (named? t1) (caddr t1) (cadr t1))) + (args2 (if (named? t2) (caddr t2) (cadr t2))) + (res1 (if (named? t1) (cdddr t1) (cddr t1))) + (res2 (if (named? t2) (cdddr t2) (cddr t2))) ) + (let loop1 ((args1 args1) + (args2 args2) + (rtype1 #f) + (rtype2 #f) + (m1 0) + (m2 0)) + (cond ((null? args1) + (and (cond ((null? args2) + (if rtype1 + (if rtype2 + (test rtype1 rtype2) + #f) + #t)) + ((eq? '#!optional (car args2)) + (not rtype1)) + ((eq? '#!rest (car args2)) + (or (null? (cdr args2)) + rtype1 + (test rtype1 (cadr args2)))) + (else (>= m2 m1))) + (let loop2 ((res1 res1) (res2 res2)) + (cond ((eq? '* res2) #t) + ((null? res2) (null? res1)) + ((eq? '* res1) #f) + ((test (car res1) (car res2)) + (loop2 (cdr res1) (cdr res2))) + (else #f))))) + ((eq? (car args1) '#!optional) + (loop1 (cdr args1) args2 #f rtype2 1 m2)) + ((eq? (car args1) '#!rest) + (if (null? (cdr args1)) + (loop1 '() args2 '* rtype2 2 m2) + (loop1 '() args2 (cadr args1) rtype2 2 m2))) + ((null? args2) + (and rtype2 + (test (car args1) rtype2) + (loop1 (cdr args1) '() rtype1 rtype2 m1 m2))) + ((eq? (car args2) '#!optional) + (loop1 args1 (cdr args2) rtype1 #f m1 1)) + ((eq? (car args2) '#!rest) + (if (null? (cdr args2)) + (loop1 args1 '() rtype1 '* m1 2) + (loop1 args1 '() rtype1 (cadr args2) m1 2))) + ((test + (or rtype1 (car args1)) + (or rtype2 (car args2))) + (loop1 (cdr args1) (cdr args2) rtype1 rtype2 m1 m2)) + (else #f))))) + (else #f))))))))))) + (set! trail trail0) + ;;(dd "type<=?: ~s <-> ~s -> ~s" t1 t2 r) + r)) ;;; various operations on procedure types @@ -1699,46 +1700,47 @@ (set-car! (cdr a) #f)))) (define (resolve t typeenv) - (let resolve ((t t) (done '())) - (cond ((assq t typeenv) => - (lambda (a) - (let ((t2 (second a))) - (if (or (not t2) - (memq t2 done)) ; circular reference - (if (third a) - (resolve (third a) (cons t done)) - '*) - (resolve t2 (cons t done)))))) - ((not (pair? t)) - (if (memq t '(* fixnum eof char string symbol float number list vector pair - undefined blob port pointer locative boolean pointer-vector - null procedure noreturn)) - t - (bomb "resolve: can't resolve unknown type-variable" t))) - (else - (case (car t) - ((or) `(or ,@(map (cut resolve <> done) (cdr t)))) - ((not) `(not ,(resolve (second t) done))) - ((forall) `(forall ,(second t) ,(resolve (third t) done))) - ((pair list vector vector-of list-of) - (cons (car t) (map (cut resolve <> done) (cdr t)))) - ((procedure) - (let* ((argtypes (procedure-arguments t)) - (rtypes (procedure-results t))) - `(procedure - ,(let loop ((args argtypes)) - (cond ((null? args) '()) - ((eq? '#!rest (car args)) - (if (equal? '(values) (cdr args)) - args - (cons (car args) (loop (cdr args))))) - ((eq? '#!optional (car args)) - (cons (car args) (loop (cdr args)))) - (else (cons (resolve (car args) done) (loop (cdr args)))))) - ,@(if (eq? '* rtypes) - '* - (map (cut resolve <> done) rtypes))))) - (else t)))))) + (simplify-type ;XXX do only when necessary + (let resolve ((t t) (done '())) + (cond ((assq t typeenv) => + (lambda (a) + (let ((t2 (second a))) + (if (or (not t2) + (memq t2 done)) ; circular reference + (if (third a) + (resolve (third a) (cons t done)) + '*) + (resolve t2 (cons t done)))))) + ((not (pair? t)) + (if (memq t '(* fixnum eof char string symbol float number list vector pair + undefined blob port pointer locative boolean pointer-vector + null procedure noreturn)) + t + (bomb "resolve: can't resolve unknown type-variable" t))) + (else + (case (car t) + ((or) `(or ,@(map (cut resolve <> done) (cdr t)))) + ((not) `(not ,(resolve (second t) done))) + ((forall) `(forall ,(second t) ,(resolve (third t) done))) + ((pair list vector vector-of list-of) + (cons (car t) (map (cut resolve <> done) (cdr t)))) + ((procedure) + (let* ((argtypes (procedure-arguments t)) + (rtypes (procedure-results t))) + `(procedure + ,(let loop ((args argtypes)) + (cond ((null? args) '()) + ((eq? '#!rest (car args)) + (if (equal? '(values) (cdr args)) + args + (cons (car args) (loop (cdr args))))) + ((eq? '#!optional (car args)) + (cons (car args) (loop (cdr args)))) + (else (cons (resolve (car args) done) (loop (cdr args)))))) + ,@(if (eq? '* rtypes) + '* + (map (cut resolve <> done) rtypes))))) + (else t))))))) ;;; type-db processing @@ -1935,26 +1937,28 @@ ((eq? 'forall (car t)) (and (= 3 (length t)) (list? (second t)) - (begin - (set! typevars - (append (map (lambda (tv) - (if (symbol? tv) tv (first tv))) - (second t)) - typevars)) - (set! constraints - (append (filter-map - (lambda (tv) - (and (pair? tv) tv)) - (second t)) - constraints)) - (and - (every (lambda (tv) - (or (symbol? tv) - (and (list? tv) - (= 2 (length tv)) - (symbol? (first tv)) - (validate (second tv))))) - (second t)) + (call/cc + (lambda (return) + (set! typevars + (append (map (lambda (tv) + (cond ((symbol? tv) tv) + ((and (list? tv) + (= 2 (length tv)) + (symbol? (car tv))) + (car tv)) + (else (return #f)))) + (second t)) + typevars)) + (set! constraints + (append (filter-map + (lambda (tv) + (and (pair? tv) + (list (car tv) + (let ((t (validate (cadr tv)))) + (unless t (return #f)) + t)))) + (second t)) + constraints)) (validate (third t) rec))))) ((eq? 'or (car t)) (and (list? t) @@ -2154,7 +2158,7 @@ ; ;XXX not used in the moment -(define (generate-type-checks! node loc vars inits) +#;(define (generate-type-checks! node loc vars inits) ;; assumes type is validated (define (test t v) (case t @@ -2269,3 +2273,62 @@ v t) ,v)))) b)))))))) + + +;;; perform check over all typevar instantiations + +(define (over-all-instantiations tlist typeenv process #!optional (combine (constantly #t))) + (let ((insts '()) + (anyinst #f) + (trail0 trail)) + + ;; restore trail and collect instantiations + (define (restore) + ;;(dd "restoring, trail: ~s, te: ~s" trail typeenv) ;XXX remove + (let ((is '())) + (do ((tr trail (cdr tr))) + ((eq? tr trail0) + (set! trail tr) + (when (pair? is) (set! anyinst #t)) + (set! insts (cons is insts))) + (set! is (alist-cons + (car tr) + (resolve (car tr) typeenv) + is)) + ;; (dd " restoring ~a, insts: ~s" (car tr) insts) ;XXX remove + (let ((a (assq (car tr) typeenv))) + (set-car! (cdr a) #f))))) + + ;; collect candidates for each typevar + (define (collect) + (let* ((vars (delete-duplicates (concatenate (map unzip1 insts)) eq?)) + ;;(_ (dd "vars: ~s, insts: ~s" vars insts)) ;XXX remove + (all (map (lambda (var) + (cons + var + (map (lambda (inst) + (cond ((assq var inst) => cdr) + (else '*))) + insts))) + vars))) + ;;(dd " collected: ~s" all) ;XXX remove + all)) + + (dd " over-all-instantiations: ~s" tlist) ;XXX remove + ;; process all tlist elements + (let loop ((ts tlist) (ok #f)) + (cond ((null? ts) + (cond ((or ok (null? tlist)) + (for-each + (lambda (i) + (set! trail (cons (car i) trail)) + (set-car! (cdr (assq (car i) typeenv)) `(or ,@(cdr i)))) + (collect)) + (combine)) + (else #f))) + ((process (car ts)) + (restore) + (loop (cdr ts) #t)) + (else + (restore) + (loop (cdr ts) ok)))))) diff --git a/tests/typematch-tests.scm b/tests/typematch-tests.scm index eb437e0b..bbb50cfc 100644 --- a/tests/typematch-tests.scm +++ b/tests/typematch-tests.scm @@ -199,3 +199,16 @@ (mx fixnum (##sys#vector-ref '#(1 2 3.4) 0)) (mx (vector fixnum float) (vector 1 2.3)) (mx (list fixnum float) (list 1 2.3)) + +(: f1 (forall (a) ((list-of a) -> a))) +(define (f1 x) (car x)) +(mx fixnum (f1 '(1))) + +(: f2 (forall (a) ((list-of a) -> a))) +(define (f2 x) (car x)) +(assert + (eq? 'sf + (compiler-typecase (f2 (list (if bar 1 'a))) + (symbol 's) + (fixnum 'f) + ((or fixnum symbol) 'sf))))Trap