Skip to content

Commit 504f11c

Browse files
committed
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`
1 parent fd5d5e9 commit 504f11c

File tree

7 files changed

+307
-105
lines changed

7 files changed

+307
-105
lines changed

typed-racket-lib/typed-racket/typecheck/tc-app/tc-app-apply.rkt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"utils.rkt"
66
syntax/parse racket/match
77
(typecheck signatures)
8-
(types abbrev utils)
8+
(types abbrev type-table utils)
99
(rep type-rep)
1010

1111
(for-label
@@ -26,7 +26,9 @@
2626
(match (single-value #'e)
2727
[(tc-result1: (ListDots: dty dbound))
2828
(ret null null null dty dbound)]
29-
[(tc-result1: (List: ts)) (ret ts)]
29+
[(tc-result1: (List: ts))
30+
(add-typeof-expr #'f (ret (->* ts (-values ts))))
31+
(ret ts)]
3032
[_ (tc/apply #'f #'(e))]))
3133
(pattern ((~or apply k:apply) f . args)
3234
(tc/apply #'f #'args)))

typed-racket-lib/typed-racket/typecheck/tc-app/tc-app-hetero.rkt

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,76 +49,91 @@
4949

5050

5151
;; FIXME - Do something with paths in the case that a structure/vector is not mutable
52-
(define (tc/hetero-ref i-e es-t vec-t name)
52+
(define (tc/hetero-ref i-e es-t vec-t name op)
5353
(define i-val (tc/index i-e))
5454
(define i-bound (length es-t))
5555
(cond
5656
[(valid-index? i-val i-bound)
57-
(ret (list-ref es-t i-val))]
57+
(define return-ty (list-ref es-t i-val))
58+
(add-typeof-expr op (ret (-> vec-t -Fixnum return-ty)))
59+
(ret return-ty)]
5860
[(not i-val)
59-
(ret (apply Un es-t))]
61+
(define return-ty (apply Un es-t))
62+
(add-typeof-expr op (ret (-> vec-t -Fixnum return-ty)))
63+
(ret return-ty)]
6064
[else
6165
(index-error i-val i-bound i-e vec-t name)]))
6266

63-
(define (tc/hetero-set! i-e es-t val-e vec-t name)
67+
(define (tc/hetero-set! i-e es-t val-e vec-t name op)
6468
(define i-val (tc/index i-e))
6569
(define i-bound (length es-t))
66-
(cond
70+
(cond
6771
[(valid-index? i-val i-bound)
68-
(tc-expr/check val-e (ret (list-ref es-t i-val)))
72+
(define val-t (list-ref es-t i-val))
73+
(tc-expr/check val-e (ret val-t))
74+
(add-typeof-expr op (ret (-> vec-t -Fixnum val-t -Void)))
6975
(ret -Void)]
7076
[(not i-val)
71-
(define val-t (single-value val-e))
77+
(define val-res (single-value val-e))
7278
(for ((es-type (in-list es-t)))
73-
(check-below val-t (ret es-type)))
79+
(check-below val-res (ret es-type)))
80+
(define val-t
81+
(match val-res [(tc-result1: t) t]))
82+
(add-typeof-expr op (ret (-> vec-t -Fixnum val-t -Void)))
7483
(ret -Void)]
7584
[else
7685
(single-value val-e)
7786
(index-error i-val i-bound i-e vec-t name)]))
7887

7988
(define-tc/app-syntax-class (tc/app-hetero expected)
8089
#:literal-sets (hetero-literals)
81-
(pattern (~and form ((~or unsafe-struct-ref unsafe-struct*-ref) struct:expr index:expr))
90+
(pattern (~and form ((~and op (~or unsafe-struct-ref unsafe-struct*-ref)) struct:expr index:expr))
8291
(match (single-value #'struct)
8392
[(tc-result1: (and struct-t (app resolve (Struct: _ _ (list (fld: flds _ _) ...) _ _ _))))
84-
(tc/hetero-ref #'index flds struct-t "struct")]
93+
(tc/hetero-ref #'index flds struct-t "struct" #'op)]
8594
[(tc-result1: (and struct-t (app resolve (Prefab: _ (list flds ...)))))
86-
(tc/hetero-ref #'index flds struct-t "prefab struct")]
95+
(tc/hetero-ref #'index flds struct-t "prefab struct" #'op)]
8796
[s-ty (tc/app-regular #'form expected)]))
8897
;; vector-ref on het vectors
89-
(pattern (~and form ((~or vector-ref unsafe-vector-ref unsafe-vector*-ref) vec:expr index:expr))
98+
(pattern (~and form ((~and op (~or vector-ref unsafe-vector-ref unsafe-vector*-ref)) vec:expr index:expr))
9099
(match (single-value #'vec)
91100
[(tc-result1: (and vec-t (app resolve (Is-a: (HeterogeneousVector: es)))))
92-
(tc/hetero-ref #'index es vec-t "vector")]
101+
(tc/hetero-ref #'index es vec-t "vector" #'op)]
93102
[v-ty (tc/app-regular #'form expected)]))
94-
;; unsafe struct-set!
95-
(pattern (~and form ((~or unsafe-struct-set! unsafe-struct*-set!) s:expr index:expr val:expr))
103+
;; unsafe struct-set!
104+
(pattern (~and form ((~and op (~or unsafe-struct-set! unsafe-struct*-set!)) s:expr index:expr val:expr))
96105
(match (single-value #'s)
97106
[(tc-result1: (and struct-t (app resolve (Struct: _ _ (list (fld: flds _ _) ...) _ _ _))))
98-
(tc/hetero-set! #'index flds #'val struct-t "struct")]
107+
(tc/hetero-set! #'index flds #'val struct-t "struct" #'op)]
99108
[s-ty (tc/app-regular #'form expected)]))
100109
;; vector-set! on het vectors
101-
(pattern (~and form ((~or vector-set! unsafe-vector-set! unsafe-vector*-set!) v:expr index:expr val:expr))
110+
(pattern (~and form ((~and op (~or vector-set! unsafe-vector-set! unsafe-vector*-set!)) v:expr index:expr val:expr))
102111
(match (single-value #'v)
103112
[(tc-result1: (and vec-t (app resolve (Is-a: (HeterogeneousVector: es)))))
104-
(tc/hetero-set! #'index es #'val vec-t "vector")]
113+
(tc/hetero-set! #'index es #'val vec-t "vector" #'op)]
105114
[v-ty (tc/app-regular #'form expected)]))
106-
(pattern (~and form ((~or vector-immutable vector) args:expr ...))
115+
(pattern (~and form ((~and op (~or vector-immutable vector)) args:expr ...))
107116
(match expected
108117
[(tc-result1: (app resolve (Is-a: (Vector: t))))
109-
(ret (make-HeterogeneousVector
110-
(for/list ([e (in-syntax #'(args ...))])
111-
(tc-expr/check e (ret t))
112-
t)))]
118+
(define arg-tys
119+
(for/list ([e (in-syntax #'(args ...))])
120+
(tc-expr/check e (ret t))
121+
t))
122+
(define return-ty
123+
(make-HeterogeneousVector arg-tys))
124+
(add-typeof-expr #'op (ret (->* arg-tys return-ty)))
125+
(ret return-ty)]
113126
[(tc-result1: (app resolve (Is-a: (HeterogeneousVector: ts))))
114127
(cond
115128
[(= (length ts) (syntax-length #'(args ...)))
116-
(ret
117-
(make-HeterogeneousVector
118-
(for/list ([e (in-syntax #'(args ...))]
119-
[t (in-list ts)])
120-
(tc-expr/check/t e (ret t))))
121-
-true-propset)]
129+
(define arg-tys
130+
(for/list ([e (in-syntax #'(args ...))]
131+
[t (in-list ts)])
132+
(tc-expr/check/t e (ret t))))
133+
(define return-ty
134+
(make-HeterogeneousVector arg-tys))
135+
(add-typeof-expr #'op (ret (->* arg-tys return-ty)))
136+
(ret return-ty -true-propset)]
122137
[else
123138
(tc-error/expr
124139
"expected vector with ~a elements, but got ~a"
@@ -136,7 +151,11 @@
136151
[_ (continue)])]
137152
;; since vectors are mutable, if there is no expected type, we want to generalize the element type
138153
[(or #f (tc-any-results: _) (tc-result1: _))
139-
(ret (make-HeterogeneousVector
140-
(for/list ((e (in-syntax #'(args ...))))
141-
(generalize (tc-expr/t e)))))]
154+
(define arg-tys
155+
(for/list ((e (in-syntax #'(args ...))))
156+
(generalize (tc-expr/t e))))
157+
(define return-ty
158+
(make-HeterogeneousVector arg-tys))
159+
(add-typeof-expr #'op (ret (->* arg-tys return-ty)))
160+
(ret return-ty)]
142161
[_ (ret Err)])))

typed-racket-lib/typed-racket/typecheck/tc-app/tc-app-list.rkt

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"utils.rkt"
77
syntax/parse syntax/stx racket/match racket/sequence
88
(typecheck signatures tc-funapp error-message)
9-
(types abbrev utils substitute)
9+
(types abbrev type-table utils substitute)
1010
(rep type-rep)
1111
(env tvar-env)
1212
(prefix-in i: (infer infer))
@@ -79,58 +79,79 @@
7979
[_ (tc/app-regular #'form expected)])))
8080
;; special case for `list'
8181
(pattern
82-
(list . args)
82+
((~and op-name list) . args)
8383
(let ([args-list (syntax->list #'args)])
84-
(match expected
85-
[(tc-result1: t)
86-
(match t
87-
[(List: ts)
88-
(cond
89-
[(= (length ts) (length args-list))
90-
(for ([arg (in-list args-list)]
91-
[t (in-list ts)])
92-
(tc-expr/check arg (ret t)))
93-
(ret t)]
94-
[else
95-
(expected-but-got t (-Tuple (map tc-expr/t args-list)))
96-
(ret t)])]
97-
[_
98-
(define vs (map (λ (_) (gensym)) args-list))
99-
(define l-type (-Tuple (map make-F vs)))
100-
;; We want to infer the largest vs that are still under the element types
101-
(define substs (i:infer vs null (list l-type) (list t) (-values (list (-> l-type Univ)))
102-
#:multiple? #t))
103-
(cond
104-
[substs
105-
(define result
106-
(for*/first ([subst (in-list substs)]
107-
[argtys (in-value (for/list ([arg (in-list args-list)]
108-
[v (in-list vs)])
109-
(tc-expr/check/t? arg (ret (subst-all subst (make-F v))))))]
110-
#:when (andmap values argtys))
111-
(ret (-Tuple argtys))))
112-
(or result
113-
(begin (expected-but-got t (-Tuple (map tc-expr/t args-list)))
114-
(fix-results expected)))]
115-
[else (ret (-Tuple (map tc-expr/t args-list)))])])]
116-
[_ (ret (-Tuple (map tc-expr/t args-list)))])))
84+
(match expected
85+
[(tc-result1: t)
86+
(match t
87+
[(List: ts)
88+
(cond
89+
[(= (length ts) (length args-list))
90+
(for ([arg (in-list args-list)]
91+
[t (in-list ts)])
92+
(tc-expr/check arg (ret t)))
93+
(add-typeof-expr #'op-name (ret (->* ts t)))
94+
(ret t)]
95+
[else
96+
(expected-but-got t (-Tuple (map tc-expr/t args-list)))
97+
(ret t)])]
98+
[_
99+
(define vs (map (λ (_) (gensym)) args-list))
100+
(define l-type (-Tuple (map make-F vs)))
101+
;; We want to infer the largest vs that are still under the element types
102+
(define substs (i:infer vs null (list l-type) (list t) (-values (list (-> l-type Univ)))
103+
#:multiple? #t))
104+
(cond
105+
[substs
106+
(define result
107+
(for*/first ([subst (in-list substs)]
108+
[arg-tys (in-value (for/list ([arg (in-list args-list)]
109+
[v (in-list vs)])
110+
(tc-expr/check/t? arg (ret (subst-all subst (make-F v))))))]
111+
#:when (andmap values arg-tys))
112+
(define return-ty (-Tuple arg-tys))
113+
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
114+
(ret return-ty)))
115+
(or result
116+
(begin (expected-but-got t (-Tuple (map tc-expr/t args-list)))
117+
(fix-results expected)))]
118+
[else
119+
(define arg-tys (map tc-expr/t args-list))
120+
(define return-ty (-Tuple arg-tys))
121+
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
122+
(ret return-ty)])])]
123+
[_
124+
(define arg-tys (map tc-expr/t args-list))
125+
(define return-ty (-Tuple arg-tys))
126+
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
127+
(ret return-ty)])))
117128
;; special case for `list*'
118-
(pattern (list* (~between args:expr 1 +inf.0) ...)
119-
(match-let* ([(list tys ... last) (stx-map tc-expr/t #'(args ...))])
120-
(ret (foldr -pair last tys))))
129+
(pattern ((~and op-name list*) (~between args:expr 1 +inf.0) ...)
130+
(match-let* ([(and arg-tys (list tys ... last)) (stx-map tc-expr/t #'(args ...))])
131+
(define return-ty (foldr -pair last tys))
132+
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
133+
(ret return-ty)))
121134
;; special case for `reverse' to propagate expected type info
122135
(pattern ((~and fun (~or reverse k:reverse)) arg)
123136
(match expected
124-
[(tc-result1: (Listof: _))
125-
(tc-expr/check #'arg expected)]
137+
[(tc-result1: (and return-ty (Listof: _)))
138+
(begin0
139+
(tc-expr/check #'arg expected)
140+
(add-typeof-expr #'fun (ret (-> return-ty return-ty))))]
126141
[(tc-result1: (List: ts))
127-
(tc-expr/check #'arg (ret (-Tuple (reverse ts))))
128-
(ret (-Tuple ts))]
142+
(define arg-ty (-Tuple (reverse ts)))
143+
(define return-ty (-Tuple ts))
144+
(tc-expr/check #'arg (ret arg-ty))
145+
(add-typeof-expr #'fun (ret (-> arg-ty return-ty)))
146+
(ret return-ty)]
129147
[_
130148
(match (single-value #'arg)
131-
[(tc-result1: (List: ts))
132-
(ret (-Tuple (reverse ts)))]
149+
[(tc-result1: (and arg-ty (List: ts)))
150+
(define return-ty (-Tuple (reverse ts)))
151+
(add-typeof-expr #'fun (ret (-> arg-ty return-ty)))
152+
(ret return-ty)]
133153
[(tc-result1: (and r (Listof: t)))
154+
(add-typeof-expr #'fun (ret (-> r r)))
134155
(ret r)]
135156
[arg-ty
136157
(tc/funapp #'fun #'(arg) (tc-expr/t #'fun) (list arg-ty) expected)])])))

typed-racket-lib/typed-racket/typecheck/tc-app/tc-app-special.rkt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@
5151
(list (ret Univ) (single-value #'arg))
5252
expected)]))
5353
;; special-case for not - flip the props
54-
(pattern ((~or false? not) arg)
54+
(pattern ((~and op-name (~or false? not)) arg)
5555
(match (single-value #'arg)
5656
[(tc-result1: t (PropSet: p+ p-) _)
57-
(ret -Boolean (make-PropSet p- p+))]))
57+
(define new-prop (make-PropSet p- p+))
58+
(add-typeof-expr #'op-name (ret (-> Univ -Boolean)))
59+
(ret -Boolean new-prop)]))
5860
;; special case for (current-contract-region)'s default expansion
5961
;; just let it through without any typechecking, since module-name-fixup
6062
;; is a private function from syntax/location, so this must have been

typed-racket-lib/typed-racket/typecheck/tc-app/tc-app-values.rkt

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
"signatures.rkt"
55
"utils.rkt"
66
syntax/parse racket/match racket/sequence
7-
(typecheck signatures tc-funapp)
8-
(types base-abbrev utils)
7+
(typecheck signatures tc-funapp tc-metafunctions)
8+
(types base-abbrev abbrev type-table utils)
9+
(rep values-rep)
910

1011
(for-label racket/base))
1112

@@ -18,34 +19,51 @@
1819
(define-tc/app-syntax-class (tc/app-values expected)
1920
#:literal-sets (values-literals)
2021
;; call-with-values
21-
(pattern (call-with-values prod con)
22-
(match (tc/funapp #'prod #'() (tc-expr/t #'prod) null #f)
22+
(pattern ((~and op-name call-with-values) prod con)
23+
#:do [(define prod-ty (tc-expr/t #'prod))]
24+
(match (tc/funapp #'prod #'() prod-ty null #f)
2325
[(tc-results: tcrs #f)
24-
(tc/funapp #'con #'(prod) (tc-expr/t #'con)
25-
(for/list ([tcr (in-list tcrs)])
26-
(-tc-results (list tcr) #f))
27-
expected)]
26+
(define con-ty (tc-expr/t #'con))
27+
(define r
28+
(tc/funapp #'con #'(prod) con-ty
29+
(for/list ([tcr (in-list tcrs)])
30+
(-tc-results (list tcr) #f))
31+
expected))
32+
(define return-ty (tc-results->values r))
33+
(add-typeof-expr #'op-name (ret (-> prod-ty con-ty return-ty)))
34+
r]
2835
[(tc-results: _ (? RestDots?))
2936
(tc-error/expr "`call-with-values` with ... is not supported")]
3037
[(tc-any-results: _)
3138
(tc/app-regular this-syntax expected)]))
3239
;; special case for `values' with single argument
3340
;; we just ignore the values, except that it forces arg to return one value
34-
(pattern (values arg)
35-
(match expected
36-
[(or #f (tc-any-results: _)) (single-value #'arg)]
37-
[(tc-result1: tp)
38-
(single-value #'arg expected)]
39-
;; Type check the argument, to find other errors
40-
[_ (single-value #'arg)]))
41+
(pattern ((~and op-name values) arg)
42+
(let ([tc-result
43+
(match expected
44+
[(or #f (tc-any-results: _))
45+
(single-value #'arg)]
46+
[(tc-result1: tp)
47+
(single-value #'arg expected)]
48+
;; Type check the argument, to find other errors
49+
[_ (single-value #'arg)])])
50+
(define arg-ty
51+
;; match never fails; `single-value` always returns a tc-result1
52+
(match tc-result [(tc-result1: t) t]))
53+
(add-typeof-expr #'op-name (ret (-> arg-ty arg-ty)))
54+
tc-result))
4155
;; handle `values' specially
42-
(pattern (values . args)
56+
(pattern ((~and op-name values) . args)
4357
(match expected
4458
[(or (tc-results: tcrs #f)
4559
(bind tcrs '()))
46-
(-tc-results
47-
(for/list ([arg (in-syntax #'args)]
48-
[tcr (in-list/rest tcrs #f)])
49-
(match (single-value arg (and tcr (-tc-results (list tcr) #f)))
50-
[(tc-results: (list res) #f) res]))
51-
#f)])))
60+
(define res
61+
(-tc-results
62+
(for/list ([arg (in-syntax #'args)]
63+
[tcr (in-list/rest tcrs #f)])
64+
(match (single-value arg (and tcr (-tc-results (list tcr) #f)))
65+
[(tc-results: (list res) #f) res])) #f))
66+
(define return-ty (tc-results->values res))
67+
(define arg-tys (match return-ty [(Values: (list (Result: t* _ _) ...)) t*]))
68+
(add-typeof-expr #'op-name (ret (->* arg-tys return-ty)))
69+
res])))

0 commit comments

Comments
 (0)