@@ -42,26 +42,70 @@ fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map,
42
42
last_uses: last_uses} ;
43
43
let visit = visit:: mk_vt ( @{
44
44
visit_expr: check_expr,
45
- visit_stmt: check_stmt
45
+ visit_stmt: check_stmt,
46
+ visit_fn_body: check_fn_body
46
47
with * visit:: default_visitor ( )
47
48
} ) ;
48
49
visit:: visit_crate ( * crate , ctx, visit) ;
49
50
tcx. sess . abort_if_errors ( ) ;
50
51
ret ctx. rval_map ;
51
52
}
52
53
53
- fn check_expr ( e : @expr, cx : ctx , v : visit:: vt < ctx > ) {
54
+ // Yields the appropriate function to check the kind of closed over
55
+ // variables. `id` is the node_id for some expression that creates the
56
+ // closure.
57
+ fn with_closure_check_fn ( cx : ctx , id : node_id ,
58
+ b : block ( fn ( ctx , ty:: t , sp : span ) ) ) {
59
+ let fty = ty:: node_id_to_monotype ( cx. tcx , id) ;
60
+ alt ty:: ty_fn_proto ( cx. tcx , fty) {
61
+ proto_send. { b ( check_send) ; }
62
+ proto_shared ( _) { b ( check_copy) ; }
63
+ proto_block. | proto_bare . { /* no check needed */ }
64
+ }
65
+ }
66
+
67
+ // Check that the free variables used in a shared/sendable closure conform
68
+ // to the copy/move kind bounds. Then recursively check the function body.
69
+ fn check_fn_body ( decl : fn_decl , body : blk , sp : span , i : fn_ident , id : node_id ,
70
+ cx : ctx , v : visit:: vt < ctx > ) {
54
71
55
- fn check_free_vars ( e : @expr,
56
- cx : ctx ,
57
- check_fn : fn ( ctx , ty:: t , sp : span ) ) {
58
- for @{ def, span} in * freevars:: get_freevars ( cx. tcx , e. id ) {
72
+ // n.b.: This could be the body of either a fn decl or a fn expr. In the
73
+ // former case, the prototype will be proto_bare and no check occurs. In
74
+ // the latter case, we do not check the variables that in the capture
75
+ // clause (as we don't have access to that here) but just those that
76
+ // appear free. The capture clauses are checked below, in check_expr().
77
+ //
78
+ // We could do this check also in check_expr(), but it seems more
79
+ // "future-proof" to do it this way, as check_fn_body() is supposed to be
80
+ // the common flow point for all functions that appear in the AST.
81
+
82
+ with_closure_check_fn ( cx, id) { |check_fn|
83
+ for @{ def, span} in * freevars:: get_freevars ( cx. tcx , id) {
59
84
let id = ast_util:: def_id_of_def ( def) . node ;
60
85
let ty = ty:: node_id_to_type ( cx. tcx , id) ;
61
86
check_fn ( cx, ty, span) ;
62
87
}
63
88
}
64
89
90
+ visit:: visit_fn_body ( decl, body, sp, i, id, cx, v) ;
91
+ }
92
+
93
+ fn check_fn_cap_clause ( _cx : ctx ,
94
+ _id : node_id ,
95
+ _cap_clause : capture_clause ) {
96
+ // let freevars = freevars::get_freevars(cx.tcx, i);
97
+ // let contains_var = lambda(id: def_id) -> bool {
98
+ // vec::any(freevars, { |freevar|
99
+ // ast_util::def_id_of_def(freevar).node == def_id
100
+ // })
101
+ // }
102
+ // with_closure_check_fn(cx, id) { |check_fn|
103
+ // let check_var = lambda(
104
+ // }
105
+ }
106
+
107
+ fn check_expr ( e : @expr, cx : ctx , v : visit:: vt < ctx > ) {
108
+
65
109
alt e. node {
66
110
expr_assign ( _, ex) | expr_assign_op ( _, _, ex) |
67
111
expr_block ( { node : { expr : some ( ex) , _} , _} ) |
@@ -121,13 +165,9 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
121
165
none. { }
122
166
}
123
167
}
124
- expr_fn ( { proto: proto_send. , _} , captures) { // NDM captures
125
- check_free_vars ( e, cx, check_send) ;
126
- }
127
- expr_fn ( { proto: proto_shared ( _) , _} , captures) { // NDM captures
128
- check_free_vars ( e, cx, check_copy) ;
129
- }
130
168
expr_ternary ( _, a, b) { maybe_copy ( cx, a) ; maybe_copy ( cx, b) ; }
169
+ expr_fn ( _, cap_clause) { check_fn_cap_clause ( cx, e. id , * cap_clause) ; }
170
+
131
171
_ { }
132
172
}
133
173
visit:: visit_expr ( e, cx, v) ;
0 commit comments