@@ -9,25 +9,26 @@ import syntax::{ast, visit};
9
9
import std:: map;
10
10
import std:: map:: hashmap;
11
11
12
- type region_map = {
13
- /* Mapping from a block to its parent block, if there is one. */
14
- parent_blocks : hashmap < ast:: node_id , ast:: node_id > ,
15
- /* Mapping from a lambda to its parent function, if there is one. */
16
- parent_fns : hashmap < ast:: node_id , ast:: node_id > ,
17
- /* Mapping from a region type in the AST to its resolved region. */
18
- ast_type_to_region : hashmap < ast:: node_id , ty:: region > ,
19
- /* Mapping from a local variable to its containing block. */
20
- local_blocks : hashmap < ast:: node_id , ast:: node_id >
21
- } ;
22
-
23
12
/* Represents the type of the most immediate parent node. */
24
13
enum parent {
25
14
pa_item( ast:: node_id ) ,
26
15
pa_block( ast:: node_id ) ,
27
- pa_alt ,
16
+ pa_nested_fn ( ast :: node_id ) ,
28
17
pa_crate
29
18
}
30
19
20
+ type region_map = {
21
+ /*
22
+ * Mapping from blocks and function expression to their parent block or
23
+ * function expression.
24
+ */
25
+ parents : hashmap < ast:: node_id , ast:: node_id > ,
26
+ /* Mapping from a region type in the AST to its resolved region. */
27
+ ast_type_to_region : hashmap < ast:: node_id , ty:: region > ,
28
+ /* Mapping from a local variable to its containing block. */
29
+ local_blocks : hashmap < ast:: node_id , ast:: node_id > ,
30
+ } ;
31
+
31
32
type ctxt = {
32
33
sess : session ,
33
34
def_map : resolve:: def_map ,
@@ -43,18 +44,29 @@ type ctxt = {
43
44
mut queued_locals : [ ast:: node_id ] ,
44
45
45
46
parent : parent ,
46
- mut parent_fn : option < ast:: node_id >
47
+
48
+ /* True if we're within the pattern part of an alt, false otherwise. */
49
+ in_alt : bool
47
50
} ;
48
51
49
- // Returns true if `subblock` is equal to or is lexically nested inside
50
- // `superblock` and false otherwise.
51
- fn block_contains ( region_map : @region_map , superblock : ast:: node_id ,
52
- subblock : ast:: node_id ) -> bool {
53
- let subblock = subblock;
54
- while superblock != subblock {
55
- alt region_map. parent_blocks . find ( subblock) {
52
+ fn region_to_scope ( _region_map : @region_map , region : ty:: region )
53
+ -> ast:: node_id {
54
+ ret alt region {
55
+ ty : : re_caller ( def_id) { def_id. node }
56
+ ty:: re_named ( _) { fail "TODO: named regions" }
57
+ ty:: re_block ( node_id) { node_id }
58
+ } ;
59
+ }
60
+
61
+ // Returns true if `subscope` is equal to or is lexically nested inside
62
+ // `superscope` and false otherwise.
63
+ fn scope_contains ( region_map : @region_map , superscope : ast:: node_id ,
64
+ subscope : ast:: node_id ) -> bool {
65
+ let subscope = subscope;
66
+ while superscope != subscope {
67
+ alt region_map. parents . find ( subscope) {
56
68
none { ret false; }
57
- some ( blk ) { subblock = blk ; }
69
+ some ( scope ) { subscope = scope ; }
58
70
}
59
71
}
60
72
ret true;
@@ -68,24 +80,21 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
68
80
ast : : re_inferred {
69
81
// We infer to the caller region if we're at item scope
70
82
// and to the block region if we're at block scope.
83
+ //
84
+ // TODO: What do we do if we're in an alt?
85
+
71
86
alt cx. parent {
72
- pa_item( item_id) {
87
+ pa_item( item_id) | pa_nested_fn ( item_id ) {
73
88
let def_id = { crate : ast:: local_crate,
74
89
node: item_id} ;
75
90
region = ty:: re_caller ( def_id) ;
76
91
}
77
92
pa_block ( block_id) {
78
93
region = ty:: re_block ( block_id) ;
79
94
}
80
- pa_alt {
81
- // FIXME: Need a design decision here.
82
- cx. sess . span_bug ( ty. span ,
83
- "what does & in an alt " +
84
- "resolve to?" ) ;
85
- }
86
95
pa_crate {
87
- cx. sess . span_bug ( ty. span ,
88
- "region type outside item " ) ;
96
+ cx. sess . span_bug ( ty. span , "inferred region at " +
97
+ "crate level?! " ) ;
89
98
}
90
99
}
91
100
}
@@ -97,16 +106,18 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
97
106
some ( def_id) { region = ty:: re_named ( def_id) ; }
98
107
none {
99
108
alt cx. parent {
100
- pa_item( _) { /* ok; fall through */ }
101
- pa_block ( _) | pa_alt {
109
+ pa_item( _) | pa_nested_fn ( _) {
110
+ /* ok; fall through */
111
+ }
112
+ pa_block ( _) {
102
113
cx. sess . span_err ( ty. span ,
103
114
"unknown region `" +
104
115
ident + "`" ) ;
105
116
}
106
117
pa_crate {
107
- cx. sess . span_bug ( ty. span ,
108
- "named region at " +
109
- "crate scope ?!" ) ;
118
+ cx. sess . span_bug ( ty. span , "named " +
119
+ "region at crate " +
120
+ "level ?!" ) ;
110
121
}
111
122
}
112
123
@@ -120,23 +131,23 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
120
131
121
132
ast:: re_self {
122
133
// For blocks, "self" means "the current block".
134
+ //
135
+ // TODO: What do we do in an alt?
136
+ //
137
+ // FIXME: Doesn't work in type items.
138
+
123
139
alt cx. parent {
124
- pa_item( _) {
125
- cx. sess . span_unimpl ( ty. span ,
126
- "'self' region for items" ) ;
140
+ pa_item( item_id) | pa_nested_fn ( item_id) {
141
+ let def_id = { crate : ast:: local_crate,
142
+ node: item_id} ;
143
+ region = ty:: re_caller ( def_id) ;
127
144
}
128
145
pa_block ( block_id) {
129
146
region = ty:: re_block ( block_id) ;
130
147
}
131
- pa_alt {
132
- // FIXME: Need a design decision here.
133
- cx. sess . span_bug ( ty. span ,
134
- "what does &self. in an alt " +
135
- "resolve to?" ) ;
136
- }
137
148
pa_crate {
138
149
cx. sess . span_bug ( ty. span ,
139
- "region type outside item" ) ;
150
+ "region type outside item?! " ) ;
140
151
}
141
152
}
142
153
}
@@ -151,28 +162,33 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
151
162
visit:: visit_ty ( ty, cx, visitor) ;
152
163
}
153
164
154
- fn resolve_block ( blk : ast :: blk , cx : ctxt , visitor : visit :: vt < ctxt > ) {
165
+ fn record_parent ( cx : ctxt , child_id : ast :: node_id ) {
155
166
alt cx. parent {
156
- pa_item ( _) | pa_alt { /* no-op */ }
157
- pa_block( parent_block_id) {
158
- cx. region_map . parent_blocks . insert ( blk. node . id , parent_block_id) ;
167
+ pa_item ( parent_id) | pa_block ( parent_id) | pa_nested_fn ( parent_id) {
168
+ cx. region_map . parents . insert ( child_id, parent_id) ;
159
169
}
160
- pa_crate { cx . sess . span_bug ( blk . span , "block outside item?!" ) ; }
170
+ pa_crate { /* no-op */ }
161
171
}
172
+ }
173
+
174
+ fn resolve_block ( blk : ast:: blk , cx : ctxt , visitor : visit:: vt < ctxt > ) {
175
+ // Record the parent of this block.
176
+ record_parent ( cx, blk. node . id ) ;
162
177
163
178
// Resolve queued locals to this block.
164
179
for local_id in cx. queued_locals {
165
180
cx. region_map . local_blocks . insert ( local_id, blk. node . id ) ;
166
181
}
167
182
183
+ // Descend.
168
184
let new_cx: ctxt = { parent: pa_block ( blk. node . id ) ,
169
- mut queued_locals: [ ] with cx} ;
185
+ mut queued_locals: [ ] ,
186
+ in_alt: false with cx} ;
170
187
visit:: visit_block ( blk, new_cx, visitor) ;
171
188
}
172
189
173
190
fn resolve_arm ( arm : ast:: arm , cx : ctxt , visitor : visit:: vt < ctxt > ) {
174
- let new_cx: ctxt = { parent: pa_alt,
175
- mut queued_locals: [ ] with cx} ;
191
+ let new_cx: ctxt = { mut queued_locals: [ ] , in_alt: true with cx} ;
176
192
visit:: visit_arm ( arm, new_cx, visitor) ;
177
193
}
178
194
@@ -190,15 +206,19 @@ fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
190
206
* containing block, depending on whether we're in an alt
191
207
* or not.
192
208
*/
193
- alt cx. parent {
194
- pa_block( block_id) {
195
- let local_blocks = cx. region_map . local_blocks ;
196
- local_blocks. insert ( pat. id , block_id) ;
197
- }
198
- pa_alt {
199
- vec : : push ( cx. queued_locals , pat. id ) ;
209
+ if cx. in_alt {
210
+ vec : : push ( cx. queued_locals , pat. id ) ;
211
+ } else {
212
+ alt cx. parent {
213
+ pa_block( block_id) {
214
+ let local_blocks = cx. region_map . local_blocks ;
215
+ local_blocks. insert ( pat. id , block_id) ;
216
+ }
217
+ _ {
218
+ cx. sess . span_bug ( pat. span ,
219
+ "unexpected parent" ) ;
220
+ }
200
221
}
201
- _ { cx. sess . span_bug ( pat. span , "unexpected parent" ) ; }
202
222
}
203
223
}
204
224
}
@@ -212,9 +232,9 @@ fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
212
232
fn resolve_expr ( expr : @ast:: expr , cx : ctxt , visitor : visit:: vt < ctxt > ) {
213
233
alt expr. node {
214
234
ast:: expr_fn ( _, _, _, _) | ast:: expr_fn_block ( _, _) {
215
- let parent_fns = cx . region_map . parent_fns ;
216
- parent_fns . insert ( expr . id , option :: get ( cx . parent_fn ) ) ;
217
- let new_cx = { parent_fn : some ( expr . id ) with cx} ;
235
+ record_parent ( cx , expr . id ) ;
236
+ let new_cx = { parent : pa_nested_fn ( expr . id ) ,
237
+ in_alt : false with cx} ;
218
238
visit:: visit_expr ( expr, new_cx, visitor) ;
219
239
}
220
240
_ { visit : : visit_expr ( expr, cx, visitor) ; }
@@ -225,7 +245,7 @@ fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
225
245
// Items create a new outer block scope as far as we're concerned.
226
246
let new_cx: ctxt = { names_in_scope: map:: new_str_hash ( ) ,
227
247
parent: pa_item ( item. id ) ,
228
- parent_fn : some ( item . id )
248
+ in_alt : false
229
249
with cx} ;
230
250
visit:: visit_item ( item, new_cx, visitor) ;
231
251
}
@@ -234,14 +254,13 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
234
254
-> @region_map {
235
255
let cx: ctxt = { sess: sess,
236
256
def_map: def_map,
237
- region_map : @{ parent_blocks : map:: new_int_hash ( ) ,
238
- parent_fns : map:: new_int_hash ( ) ,
257
+ region_map : @{ parents : map:: new_int_hash ( ) ,
239
258
ast_type_to_region : map:: new_int_hash ( ) ,
240
259
local_blocks : map:: new_int_hash ( ) } ,
241
260
names_in_scope: map:: new_str_hash ( ) ,
242
261
mut queued_locals: [ ] ,
243
262
parent: pa_crate,
244
- mut parent_fn : none } ;
263
+ in_alt : false } ;
245
264
let visitor = visit:: mk_vt ( @{
246
265
visit_block: resolve_block,
247
266
visit_item: resolve_item,
0 commit comments