@@ -10,20 +10,36 @@ import std::map;
10
10
import std:: map:: hashmap;
11
11
12
12
type region_map = {
13
+ /* Mapping from a block to its parent block, if there is one. */
13
14
parent_blocks : hashmap < ast:: node_id , ast:: node_id > ,
14
- ast_type_to_region : hashmap < ast:: node_id , ty:: region >
15
+ /* Mapping from a region type in the AST to its resolved region. */
16
+ ast_type_to_region : hashmap < ast:: node_id , ty:: region > ,
17
+ /* Mapping from a local variable to its containing block. */
18
+ local_blocks : hashmap < ast:: node_id , ast:: node_id >
15
19
} ;
16
20
21
+ /* Represents the type of the most immediate parent node. */
17
22
enum parent {
18
23
pa_item( ast:: node_id ) ,
19
24
pa_block( ast:: node_id ) ,
25
+ pa_alt,
20
26
pa_crate
21
27
}
22
28
23
29
type ctxt = {
24
30
sess : session ,
31
+ def_map : resolve:: def_map ,
25
32
region_map : @region_map ,
26
33
names_in_scope : hashmap < str , ast:: def_id > ,
34
+
35
+ /*
36
+ * A list of local IDs that will be parented to the next block we traverse.
37
+ * This is used when resolving `alt` statements. Since we see the pattern
38
+ * before the associated block, upon seeing a pattern we must parent all the
39
+ * bindings in that pattern to the next block we see.
40
+ */
41
+ mut queued_locals : [ ast:: node_id ] ,
42
+
27
43
parent : parent
28
44
} ;
29
45
@@ -44,6 +60,12 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
44
60
pa_block ( block_id) {
45
61
region = ty:: re_block ( block_id) ;
46
62
}
63
+ pa_alt {
64
+ // FIXME: Need a design decision here.
65
+ cx. sess . span_bug ( ty. span ,
66
+ "what does & in an alt " +
67
+ "resolve to?" ) ;
68
+ }
47
69
pa_crate {
48
70
cx. sess . span_bug ( ty. span ,
49
71
"region type outside item" ) ;
@@ -59,7 +81,7 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
59
81
none {
60
82
alt cx. parent {
61
83
pa_item( _) { /* ok; fall through */ }
62
- pa_block ( _) {
84
+ pa_block ( _) | pa_alt {
63
85
cx. sess . span_err ( ty. span ,
64
86
"unknown region `" +
65
87
ident + "`" ) ;
@@ -89,6 +111,12 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
89
111
pa_block ( block_id) {
90
112
region = ty:: re_block ( block_id) ;
91
113
}
114
+ pa_alt {
115
+ // FIXME: Need a design decision here.
116
+ cx. sess . span_bug ( ty. span ,
117
+ "what does &self. in an alt " +
118
+ "resolve to?" ) ;
119
+ }
92
120
pa_crate {
93
121
cx. sess . span_bug ( ty. span ,
94
122
"region type outside item" ) ;
@@ -108,17 +136,60 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
108
136
109
137
fn resolve_block ( blk : ast:: blk , cx : ctxt , visitor : visit:: vt < ctxt > ) {
110
138
alt cx. parent {
111
- pa_item ( _) { /* no-op */ }
139
+ pa_item ( _) | pa_alt { /* no-op */ }
112
140
pa_block( parent_block_id) {
113
141
cx. region_map . parent_blocks . insert ( blk. node . id , parent_block_id) ;
114
142
}
115
143
pa_crate { cx. sess . span_bug ( blk. span , "block outside item?!" ) ; }
116
144
}
117
145
118
- let new_cx: ctxt = { parent: pa_block ( blk. node . id ) with cx} ;
146
+ // Resolve queued locals to this block.
147
+ for local_id in cx. queued_locals {
148
+ cx. region_map . local_blocks . insert ( local_id, blk. node . id ) ;
149
+ }
150
+
151
+ let new_cx: ctxt = { parent: pa_block ( blk. node . id ) ,
152
+ mut queued_locals: [ ] with cx} ;
119
153
visit:: visit_block ( blk, new_cx, visitor) ;
120
154
}
121
155
156
+ fn resolve_arm ( arm : ast:: arm , cx : ctxt , visitor : visit:: vt < ctxt > ) {
157
+ let new_cx: ctxt = { parent: pa_alt,
158
+ mut queued_locals: [ ] with cx} ;
159
+ visit:: visit_arm ( arm, new_cx, visitor) ;
160
+ }
161
+
162
+ fn resolve_pat ( pat : @ast:: pat , cx : ctxt , visitor : visit:: vt < ctxt > ) {
163
+ alt pat. node {
164
+ ast:: pat_ident ( path, _) {
165
+ let defn_opt = cx. def_map . find ( pat. id ) ;
166
+ alt defn_opt {
167
+ some( ast:: def_variant ( _, _) ) {
168
+ /* Nothing to do; this names a variant. */
169
+ }
170
+ _ {
171
+ /*
172
+ * This names a local. Enqueue it or bind it to the containing
173
+ * block, depending on whether we're in an alt or not.
174
+ */
175
+ alt cx. parent {
176
+ pa_block( block_id) {
177
+ cx. region_map . local_blocks . insert ( pat. id , block_id) ;
178
+ }
179
+ pa_alt {
180
+ vec : : push ( cx. queued_locals , pat. id ) ;
181
+ }
182
+ _ { cx. sess . span_bug ( pat. span , "unexpected parent" ) ; }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ _ { /* no-op */ }
188
+ }
189
+
190
+ visit:: visit_pat ( pat, cx, visitor) ;
191
+ }
192
+
122
193
fn resolve_item ( item : @ast:: item , cx : ctxt , visitor : visit:: vt < ctxt > ) {
123
194
// Items create a new outer block scope as far as we're concerned.
124
195
let new_cx: ctxt = { names_in_scope: map:: new_str_hash ( ) ,
@@ -127,16 +198,22 @@ fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
127
198
visit:: visit_item ( item, new_cx, visitor) ;
128
199
}
129
200
130
- fn resolve_crate ( sess : session , crate : @ast:: crate ) -> @region_map {
201
+ fn resolve_crate( sess : session , def_map : resolve:: def_map , crate : @ast:: crate )
202
+ -> @region_map {
131
203
let cx: ctxt = { sess: sess,
204
+ def_map: def_map,
132
205
region_map : @{ parent_blocks : map:: new_int_hash ( ) ,
133
- ast_type_to_region : map:: new_int_hash ( ) } ,
206
+ ast_type_to_region : map:: new_int_hash ( ) ,
207
+ local_blocks : map:: new_int_hash ( ) } ,
134
208
names_in_scope: map:: new_str_hash ( ) ,
209
+ mut queued_locals: [ ] ,
135
210
parent: pa_crate} ;
136
211
let visitor = visit:: mk_vt ( @{
137
212
visit_block: resolve_block,
138
213
visit_item: resolve_item,
139
- visit_ty: resolve_ty
214
+ visit_ty: resolve_ty,
215
+ visit_arm: resolve_arm,
216
+ visit_pat: resolve_pat
140
217
with * visit:: default_visitor ( )
141
218
} ) ;
142
219
visit:: visit_crate ( * crate , cx, visitor) ;
0 commit comments