#lang racket/base (require "test-utils.rkt" rackunit racket/list (for-syntax racket/base syntax/parse) syntax/location syntax/srcloc (rep type-rep) (r:infer infer promote-demote) (types union substitute numeric-tower utils abbrev)) (provide tests) (gen-test-main) (define-syntax-rule (fv-t ty elems ...) (let ([ty* ty]) (test-check (format "~a" 'ty) equal? (fv ty*) (list (quote elems) ...)))) (begin-for-syntax (define-splicing-syntax-class result (pattern (~seq) #:with v #'#f #:with exp #'#f) (pattern (~seq #:result [v:expr exp:expr]))) (define-splicing-syntax-class vars (pattern (~seq) #:with vars #'empty) (pattern (~seq #:vars vars:expr))) (define-splicing-syntax-class indices (pattern (~seq) #:with indices #'empty) (pattern (~seq #:indices indices:expr))) (define-splicing-syntax-class pass (pattern (~seq) #:with pass #'#t) (pattern #:pass #:with pass #'#t) (pattern #:fail #:with pass #'#f))) (define-syntax (infer-t stx) (syntax-parse stx ([_ S:expr T:expr . rest] (syntax/loc stx (infer-l (list S) (list T) . rest))))) (define-syntax (infer-l stx) (syntax-parse stx ([_ S:expr T:expr :vars :indices R:result :pass] (quasisyntax/loc stx (test-case (format "~a ~a~a" S T (if pass "" " should fail")) (with-check-info (['location (build-source-location-list (quote-srcloc #,stx))]) (define substitution (infer vars indices S T R.v)) (define result (and substitution R.v (subst-all substitution R.v))) (cond [pass (unless substitution (fail-check "Could not infer a substitution")) (when result (with-check-info (['actual result] ['expected R.exp]) (unless (equal? result R.exp) (fail-check "Did not infer the expected result."))))] [fail (when substitution (fail-check "Inferred an unexpected substitution."))]))))))) (define-syntax-rule (i2-t t1 t2 (a b) ...) (test-equal? (format "~a ~a" t1 t2) (infer (fv t1) null (list t2) (list t1) (-lst* (make-F a) ...) #f) (make-immutable-hash (list (cons a (t-subst b)) ...)))) (define-syntax-rule (i2-l t1 t2 fv (a b) ...) (test-equal? (format "~a ~a" t2 t1) (infer fv null t2 t1 (-lst* (make-F a) ...) #f) (make-immutable-hash (list (cons a (t-subst b)) ...)))) (define (f t1 t2) (infer (fv t1) null (list t1) (list t2) #f)) (define-syntax-rule (i2-f t1 t2) (infer-t t2 t1 #:vars (fv t2) #:fail)) (define N -Number) (define B -Boolean) (define-syntax (pd-t stx) (syntax-parse stx ([_ S:expr (vars:id ...) D:expr P:expr] (quasisyntax/loc stx (test-case (format "~a => ~a < ~a < ~a" '(vars ...) 'D 'S 'P) (define S-v S) (define promoted (var-promote S-v '(vars ...))) (define demoted (var-demote S-v '(vars ...))) #,(syntax/loc stx (check-equal? promoted P "Promoted value doesn't match expected.")) #,(syntax/loc stx (check-equal? demoted D "Demoted value doesn't match expected."))))))) (define fv-tests (test-suite "Tests for fv" (fv-t -Number) [fv-t (-v a) a] [fv-t (-poly (a) a)] [fv-t (-poly (a b c d e) a)] [fv-t (-poly (b) (-v a)) a] [fv-t (-poly (b c d e) (-v a)) a] [fv-t (-mu a (-lst a))] [fv-t (-mu a (-lst (-pair a (-v b)))) b] [fv-t (->* null (-v a) -Number) a] ;; check that a is CONTRAVARIANT )) (define pd-tests (test-suite "Tests for var-promote/var-demote" (pd-t Univ () Univ Univ) (pd-t (-v a) () (-v a) (-v a)) (pd-t (-v a) (a) -Bottom Univ) (pd-t (-v a) (b) (-v a) (-v a)) (pd-t (-vec (-v a)) (a) (-vec -Bottom) (-vec Univ)) (pd-t (-vec (-lst (-v a))) (a) (-vec -Bottom) (-vec Univ)) (pd-t (-vec (-v a)) (b) (-vec (-v a)) (-vec (-v a))) (pd-t (-box (-v a)) (a) (-box -Bottom) (-box Univ)) (pd-t (-box (-lst (-v a))) (a) (-box -Bottom) (-box Univ)) (pd-t (-box (-v a)) (b) (-box (-v a)) (-box (-v a))) (pd-t (-channel (-v a)) (a) (-channel -Bottom) (-channel Univ)) (pd-t (-channel (-lst (-v a))) (a) (-channel -Bottom) (-channel Univ)) (pd-t (-channel (-v a)) (b) (-channel (-v a)) (-channel (-v a))) (pd-t (-thread-cell (-v a)) (a) (-thread-cell -Bottom) (-thread-cell Univ)) (pd-t (-thread-cell (-lst (-v a))) (a) (-thread-cell -Bottom) (-thread-cell Univ)) (pd-t (-thread-cell (-v a)) (b) (-thread-cell (-v a)) (-thread-cell (-v a))) (pd-t (-HT (-v a) (-v a)) (a) (-HT -Bottom -Bottom) (-HT Univ Univ)) (pd-t (-HT (-lst (-v a)) (-lst (-v a))) (a) (-HT -Bottom -Bottom) (-HT Univ Univ)) (pd-t (-HT (-v a) (-v a)) (b) (-HT (-v a) (-v a)) (-HT (-v a) (-v a))) (pd-t (-Param (-v a) (-v b)) (a b) (-Param Univ -Bottom) (-Param -Bottom Univ)) (pd-t (-Param (-lst (-v a)) (-lst (-v b))) (a b) (-Param (-lst Univ) (-lst -Bottom)) (-Param (-lst -Bottom) (-lst Univ))) (pd-t (->* (list (-lst (-v a))) (-lst (-v a)) (-lst (-v a))) (a) (->* (list (-lst Univ)) (-lst Univ) (-lst -Bottom)) (->* (list (-lst -Bottom)) (-lst -Bottom) (-lst Univ))) (pd-t (->key #:a (-lst (-v a)) #t #:b (-lst (-v a)) #f -Symbol) (a) (->key #:a (-lst Univ) #t #:b (-lst Univ) #f -Symbol) (->key #:a (-lst -Bottom) #t #:b (-lst -Bottom) #f -Symbol)) (pd-t (->... (list) ((-lst (-v a)) b) -Symbol) (a) (->... (list) ((-lst Univ) b) -Symbol) (->... (list) ((-lst -Bottom) b) -Symbol)) )) (define infer-tests (test-suite "Tests for infer" (infer-t Univ Univ) (infer-t (-v a) Univ) (infer-t (-v a) (-v a) #:result [(-v a) (-v a)]) (infer-t Univ (-v a) #:fail) (infer-t Univ (-v a) #:vars '(a)) (infer-t (-v a) Univ #:vars '(a)) (infer-t (-v a) -Bottom #:vars '(a)) (infer-t (-v a) (-v b) #:fail) (infer-t (-v a) (-v b) #:vars '(a)) (infer-t (-v a) (-v b) #:vars '(b)) (infer-t (make-ListDots -Symbol 'b) (-lst -Symbol) #:indices '(b) #:result [(make-ListDots (-v b) 'b) -Null]) (infer-t (make-ListDots (-v a) 'b) (-lst -Symbol) #:vars '(a) #:indices '(b) #:result [(-lst* (make-ListDots (-v b) 'b) (-v a)) (-lst* (-lst -Bottom) -Bottom)]) (infer-t (make-ListDots (-v b) 'b) (-lst -Symbol) #:indices '(b) #:result [(make-ListDots (-v b) 'b) (-lst -Bottom)]) (infer-t (-lst -Symbol) (make-ListDots -Symbol 'b) #:indices '(b) #:result [(make-ListDots (-v b) 'b) (-lst -Bottom)]) (infer-t (-lst -Symbol) (make-ListDots (-v b) 'b) #:indices '(b) #:result [(make-ListDots (-v b) 'b) (-lst -Symbol)]) (infer-t (make-ListDots (-v b) 'b) (-lst Univ) #:indices '(b)) (infer-t (make-ListDots (-v a) 'a) (-lst Univ)) (infer-t (make-ListDots (-lst (-v a)) 'a) (-lst (-lst Univ))) (infer-t (make-ListDots (-vec (-v a)) 'a) (-lst (-vec Univ)) #:fail) (infer-t (make-ListDots (-v a) 'b) (make-ListDots -Symbol 'b) #:vars '(a)) (infer-t (make-ListDots (-v b) 'b) (make-ListDots -Symbol 'b) #:indices '(b)) (infer-t (make-ListDots -Symbol 'b) (make-ListDots (-v b) 'b) #:indices '(b)) (infer-t (make-ListDots -Symbol 'b) (make-ListDots Univ 'b) #:indices '(b)) (infer-t (make-ListDots (-v b) 'b) (make-ListDots (-v b) 'b) #:indices '(b)) (infer-t (make-ListDots (-v b) 'b) (make-ListDots Univ 'b) #:indices '(b)) (infer-t (-pair (-v a) (make-ListDots (-v b) 'b)) (-pair (-v a) (make-ListDots (-v b) 'b)) #:result [(-v a) (-v a)]) [infer-t (->... null ((-v a) a) (-v b)) (-> -Symbol -String) #:vars '(b) #:indices '(a)] [infer-t (->... null ((-v a) a) (make-ListDots (-v a) 'a)) (-> -String -Symbol (-lst* -String -Symbol)) #:indices '(a)] [infer-t (->... (list (-v b)) ((-v a) a) (-v b)) (-> -String -Symbol -String) #:vars '(b) #:indices '(a)] [infer-t (->... (list (-v b)) ((-v a) a) (-v b)) (->... (list -Symbol) (-String a) (-v b)) #:vars '(b) #:indices '(a) #:result [(-lst* (make-ListDots (-v a) 'a) (-v b)) (-lst* (-lst -String) -Symbol)]] [infer-t (->* (list -Symbol) -String -Void) (->... (list) ((-v a) a) -Void) #:indices '(a) #:result [(-lst* (make-ListDots (-v a) 'a)) (-lst* (-lst* -Bottom #:tail (-lst -Bottom)))]] [infer-t (->* (list) -String -Void) (->... (list) (-String a) -Void)] [infer-l (list (->... null ((-v b) b) (-v a)) (-> (-v a) -Boolean)) (list (-> -String -Symbol) (-> -Symbol -Boolean)) #:vars '(a) #:indices '(b)] [infer-l (list (->... null ((-v a) a) (-v b)) (make-ListDots (-v a) 'a)) (list (-> -Symbol -Symbol -String) (-lst* -Symbol -Symbol)) #:vars '(b) #:indices '(a)] [infer-t (-> (-values (list -String))) (-> (-values-dots (list) -Symbol 'b)) #:indices '(b) #:fail] [infer-t (make-ListDots -String 'a) (make-ListDots -Symbol 'b) #:indices '(b) #:fail] [infer-t (make-ListDots -String 'a) (make-ListDots -Symbol 'b) #:indices '(a) #:fail] [infer-t (-lst* -String) (make-ListDots -Symbol 'b) #:indices '(b) #:fail] [infer-t (->* (list -Symbol) -Symbol -Void) (->* (list) (-v a) -Void) #:vars '(a) #:fail] [infer-t (-> (-values (list -Bottom))) (-> (-values (list (-v b) (-v b)))) #:vars '(a)] [infer-t (-> (-values (list (-v a)))) (-> (-values (list (-v b) (-v b)))) #:vars '(a)] [infer-t (-pair (->... (list) ((-v b) b) Univ) (make-ListDots (-lst (-v b)) 'b)) (-lst* (-> Univ Univ)) #:indices '(b) #:fail] [infer-t (-lst* (-> Univ Univ)) (-pair (->... (list) ((-v b) b) Univ) (make-ListDots (-lst (-v b)) 'b)) #:indices '(b) #:fail] [infer-t (-pair (->... (list) ((-v b) b) Univ) (make-ListDots (-v b) 'b)) (-pair (-> -Symbol Univ) (-lst -String)) #:indices '(b) #:fail] [infer-t (-pair (-> -Symbol Univ) (-lst -String)) (-pair (->... (list) ((-v b) b) Univ) (make-ListDots (-v b) 'b)) #:indices '(b) #:fail] [infer-t (-lst (-mu A (Un (-v b) (-lst A)))) (-mu C (Un (-v b2) (-lst C))) #:vars '(b2) #:result [(-vec (-v b2)) (-vec (-lst (-mu A (Un (-v b) (-lst A)))))]] [infer-t (-mlst (-val 'b)) (-mlst (-v a)) #:vars '(a) #:result [(-seq (-v a)) (-seq (-val 'b))]] [infer-t (-lst (-val (-v a))) (Un (-pair (-v a) Univ) -Null) #:vars '(a)] ;; Currently Broken ;(infer-t (make-ListDots -Symbol 'b) (-pair -Symbol (-lst -Symbol)) #:indices '(b)) [i2-t (-v a) N ('a N)] [i2-t (-pair (-v a) (-v a)) (-pair N (Un N B)) ('a (Un N B))] [i2-t (-lst (-v a)) (-lst* N N) ('a N)] [i2-t (-lst (-v a)) (-lst* N B) ('a (Un N B))] [i2-t Univ (Un N B)] [i2-t ((-v a) . -> . (-v b)) (-> N N) ('b N) ('a (Un))] [i2-t (-> (-v a) (-v a)) (->* null B B) ('a B)] [i2-l (list (-v a) (-v a) (-v b)) (list (Un (-val 1) (-val 2)) N N) '(a b) ('b N) ('a N)] [i2-l (list (-> (-v a) Univ) (-lst (-v a))) (list (-> N (Un N B)) (-lst N)) '(a) ('a N)] [i2-l (list (-> (-v a) (-v b)) (-lst (-v a))) (list (-> N N) (-lst (Un (-val 1) (-val 2)))) '(a b) ('b N) ('a (Un (-val 1) (-val 2)))] [i2-l (list (-lst (-v a))) (list (-lst (Un B N))) '(a) ('a (Un N B))] ;; error tests [i2-f (-lst (-v a)) Univ] [i2-f (->* null B B) (-> (-v a) (-v b))] )) (define tests (test-suite "All inference tests" pd-tests fv-tests infer-tests))