tc-app: add missing 'function' annotations

Update the type-table with annotations for some identifiers
 that are handled specially by `tc-app`.

Add type table tests to `unit-tests/typecheck-tests.rkt`
This commit is contained in:
Ben Greenman 2017-09-28 00:12:41 -04:00
parent fd5d5e9319
commit 504f11cc94
7 changed files with 307 additions and 105 deletions

View File

@ -5,7 +5,7 @@
"utils.rkt"
syntax/parse racket/match
(typecheck signatures)
(types abbrev utils)
(types abbrev type-table utils)
(rep type-rep)
(for-label
@ -26,7 +26,9 @@
(match (single-value #'e)
[(tc-result1: (ListDots: dty dbound))
(ret null null null dty dbound)]
[(tc-result1: (List: ts)) (ret ts)]
[(tc-result1: (List: ts))
(add-typeof-expr #'f (ret (->* ts (-values ts))))
(ret ts)]
[_ (tc/apply #'f #'(e))]))
(pattern ((~or apply k:apply) f . args)
(tc/apply #'f #'args)))

View File

@ -49,28 +49,37 @@
;; FIXME - Do something with paths in the case that a structure/vector is not mutable
(define (tc/hetero-ref i-e es-t vec-t name)
(define (tc/hetero-ref i-e es-t vec-t name op)
(define i-val (tc/index i-e))
(define i-bound (length es-t))
(cond
[(valid-index? i-val i-bound)
(ret (list-ref es-t i-val))]
(define return-ty (list-ref es-t i-val))
(add-typeof-expr op (ret (-> vec-t -Fixnum return-ty)))
(ret return-ty)]
[(not i-val)
(ret (apply Un es-t))]
(define return-ty (apply Un es-t))
(add-typeof-expr op (ret (-> vec-t -Fixnum return-ty)))
(ret return-ty)]
[else
(index-error i-val i-bound i-e vec-t name)]))
(define (tc/hetero-set! i-e es-t val-e vec-t name)
(define (tc/hetero-set! i-e es-t val-e vec-t name op)
(define i-val (tc/index i-e))
(define i-bound (length es-t))
(cond
(cond
[(valid-index? i-val i-bound)
(tc-expr/check val-e (ret (list-ref es-t i-val)))
(define val-t (list-ref es-t i-val))
(tc-expr/check val-e (ret val-t))
(add-typeof-expr op (ret (-> vec-t -Fixnum val-t -Void)))
(ret -Void)]
[(not i-val)
(define val-t (single-value val-e))
(define val-res (single-value val-e))
(for ((es-type (in-list es-t)))
(check-below val-t (ret es-type)))
(check-below val-res (ret es-type)))
(define val-t
(match val-res [(tc-result1: t) t]))
(add-typeof-expr op (ret (-> vec-t -Fixnum val-t -Void)))
(ret -Void)]
[else
(single-value val-e)
@ -78,47 +87,53 @@
(define-tc/app-syntax-class (tc/app-hetero expected)
#:literal-sets (hetero-literals)
(pattern (~and form ((~or unsafe-struct-ref unsafe-struct*-ref) struct:expr index:expr))
(pattern (~and form ((~and op (~or unsafe-struct-ref unsafe-struct*-ref)) struct:expr index:expr))
(match (single-value #'struct)
[(tc-result1: (and struct-t (app resolve (Struct: _ _ (list (fld: flds _ _) ...) _ _ _))))
(tc/hetero-ref #'index flds struct-t "struct")]
(tc/hetero-ref #'index flds struct-t "struct" #'op)]
[(tc-result1: (and struct-t (app resolve (Prefab: _ (list flds ...)))))
(tc/hetero-ref #'index flds struct-t "prefab struct")]
(tc/hetero-ref #'index flds struct-t "prefab struct" #'op)]
[s-ty (tc/app-regular #'form expected)]))
;; vector-ref on het vectors
(pattern (~and form ((~or vector-ref unsafe-vector-ref unsafe-vector*-ref) vec:expr index:expr))
(pattern (~and form ((~and op (~or vector-ref unsafe-vector-ref unsafe-vector*-ref)) vec:expr index:expr))
(match (single-value #'vec)
[(tc-result1: (and vec-t (app resolve (Is-a: (HeterogeneousVector: es)))))
(tc/hetero-ref #'index es vec-t "vector")]
(tc/hetero-ref #'index es vec-t "vector" #'op)]
[v-ty (tc/app-regular #'form expected)]))
;; unsafe struct-set!
(pattern (~and form ((~or unsafe-struct-set! unsafe-struct*-set!) s:expr index:expr val:expr))
;; unsafe struct-set!
(pattern (~and form ((~and op (~or unsafe-struct-set! unsafe-struct*-set!)) s:expr index:expr val:expr))
(match (single-value #'s)
[(tc-result1: (and struct-t (app resolve (Struct: _ _ (list (fld: flds _ _) ...) _ _ _))))
(tc/hetero-set! #'index flds #'val struct-t "struct")]
(tc/hetero-set! #'index flds #'val struct-t "struct" #'op)]
[s-ty (tc/app-regular #'form expected)]))
;; vector-set! on het vectors
(pattern (~and form ((~or vector-set! unsafe-vector-set! unsafe-vector*-set!) v:expr index:expr val:expr))
(pattern (~and form ((~and op (~or vector-set! unsafe-vector-set! unsafe-vector*-set!)) v:expr index:expr val:expr))
(match (single-value #'v)
[(tc-result1: (and vec-t (app resolve (Is-a: (HeterogeneousVector: es)))))
(tc/hetero-set! #'index es #'val vec-t "vector")]
(tc/hetero-set! #'index es #'val vec-t "vector" #'op)]
[v-ty (tc/app-regular #'form expected)]))
(pattern (~and form ((~or vector-immutable vector) args:expr ...))
(pattern (~and form ((~and op (~or vector-immutable vector)) args:expr ...))
(match expected
[(tc-result1: (app resolve (Is-a: (Vector: t))))
(ret (make-HeterogeneousVector
(for/list ([e (in-syntax #'(args ...))])
(tc-expr/check e (ret t))
t)))]
(define arg-tys
(for/list ([e (in-syntax #'(args ...))])
(tc-expr/check e (ret t))
t))
(define return-ty
(make-HeterogeneousVector arg-tys))
(add-typeof-expr #'op (ret (->* arg-tys return-ty)))
(ret return-ty)]
[(tc-result1: (app resolve (Is-a: (HeterogeneousVector: ts))))
(cond
[(= (length ts) (syntax-length #'(args ...)))
(ret
(make-HeterogeneousVector
(for/list ([e (in-syntax #'(args ...))]
[t (in-list ts)])
(tc-expr/check/t e (ret t))))
-true-propset)]
(define arg-tys
(for/list ([e (in-syntax #'(args ...))]
[t (in-list ts)])
(tc-expr/check/t e (ret t))))
(define return-ty
(make-HeterogeneousVector arg-tys))
(add-typeof-expr #'op (ret (->* arg-tys return-ty)))
(ret return-ty -true-propset)]
[else
(tc-error/expr
"expected vector with ~a elements, but got ~a"
@ -136,7 +151,11 @@
[_ (continue)])]
;; since vectors are mutable, if there is no expected type, we want to generalize the element type
[(or #f (tc-any-results: _) (tc-result1: _))
(ret (make-HeterogeneousVector
(for/list ((e (in-syntax #'(args ...))))
(generalize (tc-expr/t e)))))]
(define arg-tys
(for/list ((e (in-syntax #'(args ...))))
(generalize (tc-expr/t e))))
(define return-ty
(make-HeterogeneousVector arg-tys))
(add-typeof-expr #'op (ret (->* arg-tys return-ty)))
(ret return-ty)]
[_ (ret Err)])))

View File

@ -6,7 +6,7 @@
"utils.rkt"
syntax/parse syntax/stx racket/match racket/sequence
(typecheck signatures tc-funapp error-message)
(types abbrev utils substitute)
(types abbrev type-table utils substitute)
(rep type-rep)
(env tvar-env)
(prefix-in i: (infer infer))
@ -79,58 +79,79 @@
[_ (tc/app-regular #'form expected)])))
;; special case for `list'
(pattern
(list . args)
((~and op-name list) . args)
(let ([args-list (syntax->list #'args)])
(match expected
[(tc-result1: t)
(match t
[(List: ts)
(cond
[(= (length ts) (length args-list))
(for ([arg (in-list args-list)]
[t (in-list ts)])
(tc-expr/check arg (ret t)))
(ret t)]
[else
(expected-but-got t (-Tuple (map tc-expr/t args-list)))
(ret t)])]
[_
(define vs (map (λ (_) (gensym)) args-list))
(define l-type (-Tuple (map make-F vs)))
;; We want to infer the largest vs that are still under the element types
(define substs (i:infer vs null (list l-type) (list t) (-values (list (-> l-type Univ)))
#:multiple? #t))
(cond
[substs
(define result
(for*/first ([subst (in-list substs)]
[argtys (in-value (for/list ([arg (in-list args-list)]
[v (in-list vs)])
(tc-expr/check/t? arg (ret (subst-all subst (make-F v))))))]
#:when (andmap values argtys))
(ret (-Tuple argtys))))
(or result
(begin (expected-but-got t (-Tuple (map tc-expr/t args-list)))
(fix-results expected)))]
[else (ret (-Tuple (map tc-expr/t args-list)))])])]
[_ (ret (-Tuple (map tc-expr/t args-list)))])))
(match expected
[(tc-result1: t)
(match t
[(List: ts)
(cond
[(= (length ts) (length args-list))
(for ([arg (in-list args-list)]
[t (in-list ts)])
(tc-expr/check arg (ret t)))
(add-typeof-expr #'op-name (ret (->* ts t)))
(ret t)]
[else
(expected-but-got t (-Tuple (map tc-expr/t args-list)))
(ret t)])]
[_
(define vs (map (λ (_) (gensym)) args-list))
(define l-type (-Tuple (map make-F vs)))
;; We want to infer the largest vs that are still under the element types
(define substs (i:infer vs null (list l-type) (list t) (-values (list (-> l-type Univ)))
#:multiple? #t))
(cond
[substs
(define result
(for*/first ([subst (in-list substs)]
[arg-tys (in-value (for/list ([arg (in-list args-list)]
[v (in-list vs)])
(tc-expr/check/t? arg (ret (subst-all subst (make-F v))))))]
#:when (andmap values arg-tys))
(define return-ty (-Tuple arg-tys))
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
(ret return-ty)))
(or result
(begin (expected-but-got t (-Tuple (map tc-expr/t args-list)))
(fix-results expected)))]
[else
(define arg-tys (map tc-expr/t args-list))
(define return-ty (-Tuple arg-tys))
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
(ret return-ty)])])]
[_
(define arg-tys (map tc-expr/t args-list))
(define return-ty (-Tuple arg-tys))
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
(ret return-ty)])))
;; special case for `list*'
(pattern (list* (~between args:expr 1 +inf.0) ...)
(match-let* ([(list tys ... last) (stx-map tc-expr/t #'(args ...))])
(ret (foldr -pair last tys))))
(pattern ((~and op-name list*) (~between args:expr 1 +inf.0) ...)
(match-let* ([(and arg-tys (list tys ... last)) (stx-map tc-expr/t #'(args ...))])
(define return-ty (foldr -pair last tys))
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
(ret return-ty)))
;; special case for `reverse' to propagate expected type info
(pattern ((~and fun (~or reverse k:reverse)) arg)
(match expected
[(tc-result1: (Listof: _))
(tc-expr/check #'arg expected)]
[(tc-result1: (and return-ty (Listof: _)))
(begin0
(tc-expr/check #'arg expected)
(add-typeof-expr #'fun (ret (-> return-ty return-ty))))]
[(tc-result1: (List: ts))
(tc-expr/check #'arg (ret (-Tuple (reverse ts))))
(ret (-Tuple ts))]
(define arg-ty (-Tuple (reverse ts)))
(define return-ty (-Tuple ts))
(tc-expr/check #'arg (ret arg-ty))
(add-typeof-expr #'fun (ret (-> arg-ty return-ty)))
(ret return-ty)]
[_
(match (single-value #'arg)
[(tc-result1: (List: ts))
(ret (-Tuple (reverse ts)))]
[(tc-result1: (and arg-ty (List: ts)))
(define return-ty (-Tuple (reverse ts)))
(add-typeof-expr #'fun (ret (-> arg-ty return-ty)))
(ret return-ty)]
[(tc-result1: (and r (Listof: t)))
(add-typeof-expr #'fun (ret (-> r r)))
(ret r)]
[arg-ty
(tc/funapp #'fun #'(arg) (tc-expr/t #'fun) (list arg-ty) expected)])])))

View File

@ -51,10 +51,12 @@
(list (ret Univ) (single-value #'arg))
expected)]))
;; special-case for not - flip the props
(pattern ((~or false? not) arg)
(pattern ((~and op-name (~or false? not)) arg)
(match (single-value #'arg)
[(tc-result1: t (PropSet: p+ p-) _)
(ret -Boolean (make-PropSet p- p+))]))
(define new-prop (make-PropSet p- p+))
(add-typeof-expr #'op-name (ret (-> Univ -Boolean)))
(ret -Boolean new-prop)]))
;; special case for (current-contract-region)'s default expansion
;; just let it through without any typechecking, since module-name-fixup
;; is a private function from syntax/location, so this must have been

View File

@ -4,8 +4,9 @@
"signatures.rkt"
"utils.rkt"
syntax/parse racket/match racket/sequence
(typecheck signatures tc-funapp)
(types base-abbrev utils)
(typecheck signatures tc-funapp tc-metafunctions)
(types base-abbrev abbrev type-table utils)
(rep values-rep)
(for-label racket/base))
@ -18,34 +19,51 @@
(define-tc/app-syntax-class (tc/app-values expected)
#:literal-sets (values-literals)
;; call-with-values
(pattern (call-with-values prod con)
(match (tc/funapp #'prod #'() (tc-expr/t #'prod) null #f)
(pattern ((~and op-name call-with-values) prod con)
#:do [(define prod-ty (tc-expr/t #'prod))]
(match (tc/funapp #'prod #'() prod-ty null #f)
[(tc-results: tcrs #f)
(tc/funapp #'con #'(prod) (tc-expr/t #'con)
(for/list ([tcr (in-list tcrs)])
(-tc-results (list tcr) #f))
expected)]
(define con-ty (tc-expr/t #'con))
(define r
(tc/funapp #'con #'(prod) con-ty
(for/list ([tcr (in-list tcrs)])
(-tc-results (list tcr) #f))
expected))
(define return-ty (tc-results->values r))
(add-typeof-expr #'op-name (ret (-> prod-ty con-ty return-ty)))
r]
[(tc-results: _ (? RestDots?))
(tc-error/expr "`call-with-values` with ... is not supported")]
[(tc-any-results: _)
(tc/app-regular this-syntax expected)]))
;; special case for `values' with single argument
;; we just ignore the values, except that it forces arg to return one value
(pattern (values arg)
(match expected
[(or #f (tc-any-results: _)) (single-value #'arg)]
[(tc-result1: tp)
(single-value #'arg expected)]
;; Type check the argument, to find other errors
[_ (single-value #'arg)]))
(pattern ((~and op-name values) arg)
(let ([tc-result
(match expected
[(or #f (tc-any-results: _))
(single-value #'arg)]
[(tc-result1: tp)
(single-value #'arg expected)]
;; Type check the argument, to find other errors
[_ (single-value #'arg)])])
(define arg-ty
;; match never fails; `single-value` always returns a tc-result1
(match tc-result [(tc-result1: t) t]))
(add-typeof-expr #'op-name (ret (-> arg-ty arg-ty)))
tc-result))
;; handle `values' specially
(pattern (values . args)
(pattern ((~and op-name values) . args)
(match expected
[(or (tc-results: tcrs #f)
(bind tcrs '()))
(-tc-results
(for/list ([arg (in-syntax #'args)]
[tcr (in-list/rest tcrs #f)])
(match (single-value arg (and tcr (-tc-results (list tcr) #f)))
[(tc-results: (list res) #f) res]))
#f)])))
(define res
(-tc-results
(for/list ([arg (in-syntax #'args)]
[tcr (in-list/rest tcrs #f)])
(match (single-value arg (and tcr (-tc-results (list tcr) #f)))
[(tc-results: (list res) #f) res])) #f))
(define return-ty (tc-results->values res))
(define arg-tys (match return-ty [(Values: (list (Result: t* _ _) ...)) t*]))
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
res])))

View File

@ -3,7 +3,7 @@
(require (rename-in "../utils/utils.rkt" [infer r:infer])
racket/match racket/list
(typecheck signatures tc-app-helper)
(types utils abbrev substitute)
(types utils abbrev substitute type-table)
(utils tc-utils)
(rep type-rep core-rep values-rep)
(r:infer infer))
@ -67,8 +67,9 @@
;; Takes a possible substitution and comuptes
;; the substituted range type if it is not #f
(define (finish substitution)
(and substitution (do-ret (subst-all substitution rng))))
(begin0
(and substitution (do-ret (subst-all substitution rng)))
(add-typeof-expr f (ret (make-Fun (list arrow))))))
(finish
(infer vars dotted-vars
(list (-Tuple* arg-tys full-tail-ty))

View File

@ -42,14 +42,17 @@
"test-utils.rkt"
typed-racket/utils/utils
racket/base racket/match
syntax/id-table
(rep core-rep)
(rename-in (types prop-ops tc-result printer subtype) [ret raw-ret])
(only-in (types type-table) type-of)
syntax/parse
(for-template (only-in typed-racket/typed-racket do-standard-inits))
(typecheck typechecker check-below tc-metafunctions)
(utils mutated-vars tc-utils)
(env lexical-env mvar-env))
(provide
test-type-table
test-literal test-literal/fail
test test/proc test/fail)
@ -122,6 +125,38 @@
(define golden (golden-fun expanded-expr))
(check-tc-results result golden #:name "tc-expr"))
;; test-type-table : syntax? (listof (cons/c identifier? tc-results?)) -> void?
;; Typecheck the given expression
;; and assert that the type-table has an entry for every identifier
;; in the given association list.
;;
;; Example: `(test-type-table expr (list (cons f t)))` will
;; 1. type-check `expr`
;; 2. search `expr` for occurrences of `f`
;; 3. check that the type-table entry for `f` matches `t`
(define (test-type-table expr assoc)
(define expanded-expr
(let ([expr+ (tr-expand expr)])
(begin (tc expr+ #f) expr+)))
(define expected-results
(make-free-id-table assoc))
(let loop ([x expanded-expr]) ;; loop : any/c -> void?
(cond
[(and (identifier? x)
(free-id-table-ref expected-results x #f))
=> (λ (expected)
(define actual (type-of x))
(define test-name (format "(type-of ~a)" (syntax-e x)))
(check-tc-results actual expected #:name test-name))]
[(syntax? x)
(loop (syntax-e x))]
[(list? x)
(map loop x)]
[(pair? x)
(loop (car x))
(loop (cdr x))]
[else
(void)])))
;; test/fail syntax? tc-results? (or/c string? regexp?) (option/c tc-results?)
;; [(listof (list id type))] -> void?
@ -278,6 +313,15 @@
(test-phase1 #,(syntax/loc #'lit (LITERAL/FAIL lit))
(test-literal/fail (quote-syntax lit) msg.v ex.v)))]))
(define-syntax (tc/type-table stx)
(syntax-parse stx
[(_ e:expr ([k v] ...))
(quasisyntax/loc stx
(test-phase1 e
(test-type-table
(quote-syntax e)
(list (cons (quote-syntax k) (ret v)) ...))))]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -4490,4 +4534,99 @@
(-prefab 'foo (-opt -String))
#:expected (-prefab 'foo (-opt -String))]
)
(test-suite
"type-table tests"
;; tc-app-apply
(tc/type-table (apply values '(0))
([values (t:-> (-val 0) (-val 0))]))
(tc/type-table (apply + '(0))
([values (t:-> (-val 0) (-val 0))]))
;; tc-app-hetero
(tc/type-table (void ;; vector-ref on heterogeneous vectors
(vector-ref (ann '#(A B) (Vector 'A 'B)) 0)
(unsafe-vector-ref (ann (vector 'A 'B) (Vector 'A 'B)) 0)
(unsafe-vector*-ref (ann (vector 'A 'B) (Vector 'A 'B)) 1))
([vector-ref (t:-> (-vec* (-val 'A) (-val 'B)) -Fixnum (-val 'A))]
[unsafe-vector-ref (t:-> (-vec* (-val 'A) (-val 'B)) -Fixnum (-val 'A))]
[unsafe-vector*-ref (t:-> (-vec* (-val 'A) (-val 'B)) -Fixnum (-val 'B))]))
(tc/type-table (void ;; vector-set! on heterogeneous vectors
(vector-set! (ann (vector 'A 'B) (Vector Symbol 'B)) 0 'X)
(unsafe-vector-set! (ann (vector 'C 'D) (Vector Symbol 'D)) 0 'X)
(unsafe-vector*-set! (ann (vector 'E 'F) (Vector 'E Symbol)) 1 'X))
([vector-set! (t:-> (-vec* -Symbol (-val 'B)) -Fixnum -Symbol -Void)]
[unsafe-vector-set! (t:-> (-vec* -Symbol (-val 'D)) -Fixnum -Symbol -Void)]
[unsafe-vector*-set! (t:-> (-vec* (-val 'E) -Symbol) -Fixnum -Symbol -Void)]))
(tc/type-table (vector-set! (ann (vector 'a 'b) (Vector Symbol Symbol)) (+ -1 2) 'c)
;; test when the index for vector-set! isn't know
([vector-set! (t:-> (-vec* -Symbol -Symbol) -Fixnum (-val 'c) -Void)]))
(tc/type-table (void ;; vector constructor, returning heterogeneous vector
(ann (vector 'A 'B) (Vectorof Symbol))
(ann (vector-immutable 'A 'B) (Vectorof Symbol)))
([vector (t:-> -Symbol -Symbol (-vec* -Symbol -Symbol))]
[vector-immutable (t:-> -Symbol -Symbol (-vec* -Symbol -Symbol))]))
(tc/type-table (void ;; vector constructor, returning heterogeneous vector
(ann (vector 'A 'B) (Vector 'A 'B))
(ann (vector-immutable 'A 'B) (Vector 'A 'B)))
([vector (t:-> (-val 'A) (-val 'B) (-vec* (-val 'A) (-val 'B)))]
[vector-immutable (t:-> (-val 'A) (-val 'B) (-vec* (-val 'A) (-val 'B)))]))
(tc/type-table (void ;; vector constructor, no expected type
(vector 'A 'B)
(vector-immutable 'A 'B))
([vector (t:-> -Symbol -Symbol (-vec* -Symbol -Symbol))]
[vector-immutable (t:-> -Symbol -Symbol (-vec* -Symbol -Symbol))]))
;; tc-app-list
;;; list
(tc/type-table (ann (list 'A 'B) (List Symbol Symbol))
([list (t:-> -Symbol -Symbol (-lst* -Symbol -Symbol))]))
(tc/type-table (ann (list 'A) Any)
([list (t:-> Univ (-lst* Univ))]))
(tc/type-table (list 'A 'B)
([list (t:-> (-val 'A) (-val 'B) (-lst* (-val 'A) (-val 'B)))]))
;;; list*
(tc/type-table (list* #true #false)
([list* (t:-> (-val #true) (-val #false) (-pair (-val #true) (-val #false)))]))
(tc/type-table (list* "A" "B" (list "C"))
([list* (t:-> -String -String (-lst* -String) (-lst* -String -String -String))]))
;;; reverse
(tc/type-table (ann (reverse '("A" "B")) (Listof String))
([reverse (t:-> (-lst -String) (-lst -String))]))
(tc/type-table (ann (reverse '(A B)) (List 'B 'A))
([reverse (t:-> (-lst* (-val 'A) (-val 'B)) (-lst* (-val 'B) (-val 'A)))]))
(tc/type-table (reverse (ann '(A B) (List 'A 'B)))
([reverse (t:-> (-lst* (-val 'A) (-val 'B)) (-lst* (-val 'B) (-val 'A)))]))
(tc/type-table (reverse (ann '("A" "B") (Listof String)))
([reverse (t:-> (-lst -String) (-lst -String))]))
;; tc-app-special
(tc/type-table (false? #true)
([false? (t:-> Univ -Boolean)]))
(tc/type-table (false? #false)
([false? (t:-> Univ -Boolean)]))
(tc/type-table (not #true)
([not (t:-> Univ -Boolean)]))
(tc/type-table (not #false)
([not (t:-> Univ -Boolean)]))
;; tc-app-values
(tc/type-table (values 0)
([values (t:-> (-val 0) (-values (list (-val 0))))]))
;; TODO tests fail because propsets are somehow different (2017-12-06)
;(tc/type-table (values 0 0)
; ([values (t:-> (-val 0) (-val 0) (-values (list (-val 0 ) (-val 0))))]))
;(tc/type-table (call-with-values (λ () 'A) symbol->string)
; ([call-with-values (->* (list (t:-> (-val 'A)) (t:-> -Symbol -String)) -String)]))
;(tc/type-table (call-with-values (λ () "hello") (λ: ((x : String)) "world"))
; ([call-with-values (t:-> (t:-> -String) (t:-> -String -String) -String)]))
;(tc/type-table (call-with-values (λ () (values 0 0)) (λ: ((x : Zero) (y : Zero)) 0))
; ([call-with-values (t:-> (t:-> (-values (list (-val 0) (-val 0))))
; (t:-> (-val 0) (-val 0) (-val 0))
; (-val 0))]))
;(tc/type-table (call-with-values (λ () (values "a" "b")) (λ: ((x : String) (y : String)) (string-append x y)))
; ([call-with-values (t:-> (t:-> (-values (list -String -String)))
; (t:-> -String -String -String)
; -String)]))
)
))