@@ -15,127 +15,99 @@ import middle::resolve;
15
15
import syntax:: codemap:: span;
16
16
17
17
export annotate_freevars;
18
- export freevar_set;
19
18
export freevar_map;
20
- export get_freevar_info;
21
19
export get_freevars;
22
- export get_freevar_defs;
23
20
export has_freevars;
24
- export is_freevar_of;
25
- export def_lookup;
26
21
27
- // Throughout the compiler, variables are generally dealt with using the
28
- // node_ids of the reference sites and not the def_id of the definition
29
- // site. Thus we store a set are the definitions along with a vec of one
30
- // "canonical" referencing node_id per free variable. The set is useful for
31
- // testing membership, the list of referencing sites is what you want for most
32
- // other things.
33
- type freevar_set = hashset < ast:: node_id > ;
34
- type freevar_info = { defs : freevar_set , refs : @[ ast:: node_id ] } ;
22
+ // A vector of defs representing the free variables referred to in a function.
23
+ // (The def_upvar will already have been stripped).
24
+ type freevar_info = @[ ast:: def ] ;
35
25
type freevar_map = hashmap < ast:: node_id , freevar_info > ;
36
26
37
27
// Searches through part of the AST for all references to locals or
38
28
// upvars in this frame and returns the list of definition IDs thus found.
39
29
// Since we want to be able to collect upvars in some arbitrary piece
40
30
// of the AST, we take a walker function that we invoke with a visitor
41
31
// in order to start the search.
42
- fn collect_freevars ( def_map : & resolve:: def_map , sess : & session:: session ,
43
- walker : & fn ( & visit:: vt < ( ) > ) ,
44
- initial_decls : [ ast:: node_id ] ) -> freevar_info {
45
- let decls = new_int_hash ( ) ;
46
- for decl: ast:: node_id in initial_decls { set_add ( decls, decl) ; }
32
+ fn collect_freevars ( def_map : & resolve:: def_map ,
33
+ walker : & fn ( & visit:: vt < int > ) ) -> freevar_info {
34
+ let seen = new_int_hash ( ) ;
47
35
let refs = @mutable [ ] ;
48
36
49
- let walk_fn =
50
- lambda ( f: & ast:: _fn, _tps: & [ ast:: ty_param] , _sp: & span,
51
- _i: & ast:: fn_ident, _nid: ast:: node_id) {
52
- for a: ast:: arg in f. decl . inputs { set_add ( decls, a. id ) ; }
53
- } ;
54
- let walk_expr =
55
- lambda ( expr: & @ast:: expr) {
56
- alt expr. node {
57
- ast:: expr_path ( path) {
58
- if !def_map. contains_key ( expr. id ) {
59
- sess. span_fatal ( expr. span ,
60
- ~"internal error in collect_freevars") ;
61
- }
62
- alt def_map. get ( expr. id ) {
63
- ast:: def_arg ( did, _) { * refs += [ expr. id ] ; }
64
- ast:: def_local ( did) { * refs += [ expr. id ] ; }
65
- ast:: def_binding ( did) { * refs += [ expr. id ] ; }
66
- _ { /* no-op */ }
37
+ fn ignore_item ( _i : & @ast:: item , _depth : & int , _v : & visit:: vt < int > ) { }
38
+
39
+ let walk_expr = lambda ( expr: & @ast:: expr, depth: & int,
40
+ v: & visit:: vt<int>) {
41
+ alt expr. node {
42
+ ast:: expr_fn ( f) {
43
+ if f. proto == ast:: proto_block ||
44
+ f. proto == ast:: proto_closure {
45
+ visit:: visit_expr ( expr, depth + 1 , v) ;
46
+ }
47
+ }
48
+ ast:: expr_for_each ( dcl, x, b) {
49
+ v. visit_local ( dcl, depth, v) ;
50
+ v. visit_expr ( x, depth, v) ;
51
+ v. visit_block ( b, depth + 1 , v) ;
52
+ }
53
+ ast:: expr_path ( path) {
54
+ let def = def_map. get ( expr. id ) , i = 0 ;
55
+ while i < depth {
56
+ alt { def} {
57
+ ast:: def_upvar ( _, inner, _) {
58
+ def = * inner;
59
+ }
60
+ _ { break; }
67
61
}
68
- }
69
- _ { }
62
+ i += 1 ;
70
63
}
71
- } ;
72
- let walk_local =
73
- lambda ( local: & @ast:: local) {
74
- for each b: @ast:: pat in ast_util:: pat_bindings ( local. node . pat ) {
75
- set_add ( decls, b. id ) ;
64
+ if i == depth { // Made it to end of loop
65
+ let dnum = ast_util:: def_id_of_def ( def) . node ;
66
+ if !seen. contains_key ( dnum) {
67
+ * refs += [ def] ;
68
+ seen. insert ( dnum, ( ) ) ;
69
+ }
76
70
}
77
- } ;
78
- let walk_pat =
79
- lambda ( p: & @ast:: pat) {
80
- alt p. node { ast:: pat_bind ( _) { set_add ( decls, p. id ) ; } _ { } }
81
- } ;
82
-
83
- walker ( visit:: mk_simple_visitor ( @{ visit_local: walk_local,
84
- visit_pat: walk_pat,
85
- visit_expr: walk_expr,
86
- visit_fn: walk_fn
87
- with
88
- * visit:: default_simple_visitor ( ) } ) ) ;
89
- // Calculate (refs - decls). This is the set of captured upvars.
90
- // We build a vec of the node ids of the uses and a set of the
91
- // node ids of the definitions.
92
- let canonical_refs = [ ] ;
93
- let defs = new_int_hash ( ) ;
94
- for ref_id_: ast:: node_id in * refs {
95
- let ref_id = ref_id_;
96
- let def_id = ast_util:: def_id_of_def ( def_map. get ( ref_id) ) . node ;
97
- if !decls. contains_key ( def_id) && !defs. contains_key ( def_id) {
98
- canonical_refs += [ ref_id] ;
99
- set_add ( defs, def_id) ;
71
+ }
72
+ _ { visit : : visit_expr ( expr, depth, v) ; }
100
73
}
101
- }
102
- ret { defs : defs, refs : @canonical_refs} ;
74
+ } ;
75
+
76
+ walker ( visit:: mk_vt ( @{ visit_item: ignore_item,
77
+ visit_expr: walk_expr
78
+ with * visit:: default_visitor ( ) } ) ) ;
79
+ ret @* refs;
103
80
}
104
81
105
82
// Build a map from every function and for-each body to a set of the
106
83
// freevars contained in it. The implementation is not particularly
107
84
// efficient as it fully recomputes the free variables at every
108
85
// node of interest rather than building up the free variables in
109
86
// one pass. This could be improved upon if it turns out to matter.
110
- fn annotate_freevars ( sess : & session :: session , def_map : & resolve:: def_map ,
87
+ fn annotate_freevars ( def_map : & resolve:: def_map ,
111
88
crate : & @ast:: crate ) -> freevar_map {
112
89
let freevars = new_int_hash ( ) ;
113
90
114
- let walk_fn =
115
- lambda ( f: & ast:: _fn, tps: & [ ast:: ty_param] , sp: & span,
116
- i: & ast:: fn_ident, nid: ast:: node_id) {
117
- let start_walk =
118
- lambda ( v: & visit:: vt<( ) >) {
119
- v. visit_fn ( f, tps, sp, i, nid, ( ) , v) ;
120
- } ;
121
- let vars = collect_freevars ( def_map, sess, start_walk, [ ] ) ;
122
- freevars. insert ( nid, vars) ;
123
- } ;
124
- let walk_expr =
125
- lambda ( expr: & @ast:: expr) {
126
- alt expr. node {
127
- ast:: expr_for_each ( local, _, body) {
128
- let start_walk =
129
- lambda ( v: & visit:: vt<( ) >) {
130
- v. visit_block ( body, ( ) , v) ;
131
- } ;
132
- let bound = ast_util:: pat_binding_ids ( local. node . pat ) ;
133
- let vars = collect_freevars ( def_map, sess, start_walk, bound) ;
134
- freevars. insert ( body. node . id , vars) ;
135
- }
136
- _ { }
137
- }
91
+ let walk_fn = lambda ( f: & ast:: _fn, tps: & [ ast:: ty_param] , sp: & span,
92
+ i: & ast:: fn_ident, nid: ast:: node_id) {
93
+ let start_walk = lambda ( v: & visit:: vt<int>) {
94
+ v. visit_fn ( f, tps, sp, i, nid, 1 , v) ;
138
95
} ;
96
+ let vars = collect_freevars ( def_map, start_walk) ;
97
+ freevars. insert ( nid, vars) ;
98
+ } ;
99
+ let walk_expr = lambda ( expr: & @ast:: expr) {
100
+ alt expr. node {
101
+ ast:: expr_for_each ( local, _, body) {
102
+ let start_walk = lambda ( v: & visit:: vt<int>) {
103
+ v. visit_block ( body, 1 , v) ;
104
+ } ;
105
+ let vars = collect_freevars ( def_map, start_walk) ;
106
+ freevars. insert ( body. node . id , vars) ;
107
+ }
108
+ _ { }
109
+ }
110
+ } ;
139
111
140
112
let visitor =
141
113
visit:: mk_simple_visitor ( @{ visit_fn: walk_fn, visit_expr: walk_expr
@@ -145,7 +117,7 @@ fn annotate_freevars(sess: &session::session, def_map: &resolve::def_map,
145
117
ret freevars;
146
118
}
147
119
148
- fn get_freevar_info ( tcx : & ty:: ctxt , fid : ast:: node_id ) -> freevar_info {
120
+ fn get_freevars ( tcx : & ty:: ctxt , fid : ast:: node_id ) -> freevar_info {
149
121
alt tcx. freevars . find ( fid) {
150
122
none. {
151
123
fail "get_freevars: " + istr:: to_estr ( int:: str ( fid) )
@@ -154,31 +126,9 @@ fn get_freevar_info(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_info {
154
126
some ( d) { ret d; }
155
127
}
156
128
}
157
- fn get_freevar_defs ( tcx : & ty:: ctxt , fid : ast:: node_id ) -> freevar_set {
158
- ret get_freevar_info ( tcx, fid) . defs ;
159
- }
160
- fn get_freevars ( tcx : & ty:: ctxt , fid : ast:: node_id ) -> @[ ast:: node_id ] {
161
- ret get_freevar_info ( tcx, fid) . refs ;
162
- }
163
129
fn has_freevars ( tcx : & ty:: ctxt , fid : ast:: node_id ) -> bool {
164
- ret get_freevar_defs ( tcx, fid) . size ( ) != 0 u;
130
+ ret std :: vec :: len ( * get_freevars ( tcx, fid) ) != 0 u;
165
131
}
166
- fn is_freevar_of ( tcx : & ty:: ctxt , def : ast:: node_id , f : ast:: node_id ) -> bool {
167
- ret get_freevar_defs ( tcx, f) . contains_key ( def) ;
168
- }
169
- fn def_lookup ( tcx : & ty:: ctxt , f : ast:: node_id , id : ast:: node_id ) ->
170
- option:: t < ast:: def > {
171
- alt tcx. def_map . find ( id) {
172
- none. { ret none ; }
173
- some ( d) {
174
- let did = ast_util:: def_id_of_def ( d) ;
175
- if f != -1 && is_freevar_of ( tcx, did. node , f) {
176
- ret some ( ast:: def_upvar ( did, @d) ) ;
177
- } else { ret some ( d) ; }
178
- }
179
- }
180
- }
181
-
182
132
183
133
// Local Variables:
184
134
// mode: rust
0 commit comments