1
- // A pass that annotates for each loops with the free variables that
2
- // they contain.
1
+ // A pass that annotates for each loops and functions with the free
2
+ // variables that they contain.
3
3
4
4
import std:: map;
5
5
import std:: map:: * ;
6
6
import syntax:: ast;
7
7
import syntax:: walk;
8
8
import driver:: session;
9
- import middle:: ty ;
9
+ import middle:: resolve ;
10
10
import syntax:: codemap:: span;
11
11
12
+ export annotate_freevars;
13
+ export freevar_set;
14
+ export freevar_map;
12
15
16
+ type freevar_set = ast:: node_id [ ] ;
17
+ type freevar_map = hashmap [ ast:: node_id, freevar_set] ;
13
18
14
19
// Searches through part of the AST for all references to locals or
15
20
// upvars in this frame and returns the list of definition IDs thus found.
16
21
// Since we want to be able to collect upvars in some arbitrary piece
17
22
// of the AST, we take a walker function that we invoke with a visitor
18
23
// in order to start the search.
19
- fn collect_upvars( & ty:: ctxt tcx, & fn ( & walk:: ast_visitor ) walker,
20
- ast:: node_id[ ] initial_decls) -> ast:: node_id [ ] {
24
+ fn collect_freevars( & resolve:: def_map def_map, & session:: session sess,
25
+ & fn ( & walk:: ast_visitor ) walker,
26
+ ast:: node_id[ ] initial_decls) -> ast:: node_id [ ] {
21
27
type env =
22
28
@rec( mutable ast:: node_id[ ] refs,
23
29
hashmap[ ast:: node_id, ( ) ] decls,
@@ -33,7 +39,7 @@ fn collect_upvars(&ty::ctxt tcx, &fn (&walk::ast_visitor) walker,
33
39
case ( ast:: expr_path( ?path) ) {
34
40
if ( ! e. def_map. contains_key( expr. id) ) {
35
41
e. sess. span_fatal( expr. span,
36
- "internal error in collect_upvars " ) ;
42
+ "internal error in collect_freevars " ) ;
37
43
}
38
44
alt ( e. def_map. get( expr. id) ) {
39
45
case ( ast:: def_arg( ?did) ) { e. refs += ~[ did. _1] ; }
@@ -62,17 +68,17 @@ fn collect_upvars(&ty::ctxt tcx, &fn (&walk::ast_visitor) walker,
62
68
let env e =
63
69
@rec( mutable refs=~[ ] ,
64
70
decls=decls,
65
- def_map=tcx . def_map,
66
- sess=tcx . sess) ;
71
+ def_map=def_map,
72
+ sess=sess) ;
67
73
auto visitor =
68
74
@rec( visit_fn_pre=bind walk_fn( e, _, _, _, _, _) ,
69
75
visit_local_pre=bind walk_local( e, _) ,
70
76
visit_expr_pre=bind walk_expr( e, _) ,
71
77
visit_pat_pre=bind walk_pat( e, _)
72
78
with walk:: default_visitor( ) ) ;
73
79
walker( * visitor) ;
74
- // Calculate (refs - decls). This is the set of captured upvars.
75
80
81
+ // Calculate (refs - decls). This is the set of captured upvars.
76
82
let ast:: node_id[ ] result = ~[ ] ;
77
83
for ( ast:: node_id ref_id_ in e. refs) {
78
84
auto ref_id = ref_id_;
@@ -81,6 +87,47 @@ fn collect_upvars(&ty::ctxt tcx, &fn (&walk::ast_visitor) walker,
81
87
ret result;
82
88
}
83
89
90
+ // Build a map from every function and for-each body to a set of the
91
+ // freevars contained in it. The implementation is not particularly
92
+ // efficient as it fully recomputes the free variables at every
93
+ // node of interest rather than building up the free variables in
94
+ // one pass. This could be improved upon if it turns out to matter.
95
+ fn annotate_freevars( & session:: session sess, & resolve:: def_map def_map,
96
+ & @ast:: crate crate) -> freevar_map {
97
+ type env =
98
+ rec( freevar_map freevars,
99
+ resolve:: def_map def_map,
100
+ session:: session sess) ;
101
+
102
+ fn walk_fn( env e, & ast:: _fn f, & ast:: ty_param[ ] tps, & span sp,
103
+ & ast:: fn_ident i, ast:: node_id nid) {
104
+ auto walker = bind walk : : walk_fn( _, f, tps, sp, i, nid) ;
105
+ auto vars = collect_freevars( e. def_map, e. sess, walker, ~[ ] ) ;
106
+ e. freevars. insert( nid, vars) ;
107
+ }
108
+ fn walk_expr( env e, & @ast:: expr expr) {
109
+ alt ( expr. node) {
110
+ ast:: expr_for_each( ?local, _, ?body) {
111
+ auto vars = collect_freevars( e. def_map, e. sess,
112
+ bind walk:: walk_block( _, body) ,
113
+ ~[ local. node. id] ) ;
114
+ e. freevars. insert( body. node. id, vars) ;
115
+ }
116
+ _ { }
117
+ }
118
+ }
119
+
120
+ let env e =
121
+ rec( freevars = new_int_hash( ) , def_map=def_map, sess=sess) ;
122
+ auto visitor =
123
+ rec( visit_fn_pre=bind walk_fn( e, _, _, _, _, _) ,
124
+ visit_expr_pre=bind walk_expr( e, _)
125
+ with walk:: default_visitor( ) ) ;
126
+ walk:: walk_crate( visitor, * crate ) ;
127
+
128
+ ret e. freevars;
129
+ }
130
+
84
131
// Local Variables:
85
132
// mode: rust
86
133
// fill-column: 78;
0 commit comments