@@ -162,43 +162,38 @@ type ctxt = {
162
162
def_map : resolve:: def_map ,
163
163
region_map : region_map ,
164
164
165
- // These two fields (parent and closure_parent) specify the parent
166
- // scope of the current expression. The parent scope is the
167
- // innermost block, call, or alt expression during the execution
168
- // of which the current expression will be evaluated. Generally
169
- // speaking, the innermost parent scope is also the closest
170
- // suitable ancestor in the AST tree.
165
+ // The parent scope is the innermost block, call, or alt
166
+ // expression during the execution of which the current expression
167
+ // will be evaluated. Generally speaking, the innermost parent
168
+ // scope is also the closest suitable ancestor in the AST tree.
171
169
//
172
- // However, there are two subtle cases where the parent scope for
173
- // an expression is not strictly derived from the AST. The first
174
- // such exception concerns call arguments and the second concerns
175
- // closures (which, at least today, are always call arguments).
176
- // Consider:
170
+ // There is a subtle point concerning call arguments. Imagine
171
+ // you have a call:
177
172
//
178
173
// { // block a
179
- // foo( // call b
174
+ // foo( // call b
180
175
// x,
181
- // y,
182
- // fn&() {
183
- // // fn body c
184
- // })
176
+ // y);
185
177
// }
186
178
//
187
- // Here, the parent of the three argument expressions is
188
- // actually the block `a`, not the call `b`, because they will
189
- // be evaluated before the call conceptually takes place.
190
- // However, the body of the closure is parented by the call
191
- // `b` (it cannot be invoked except during that call, after
192
- // all).
179
+ // In what lifetime are the expressions `x` and `y` evaluated? At
180
+ // first, I imagine the answer was the block `a`, as the arguments
181
+ // are evaluated before the call takes place. But this turns out
182
+ // to be wrong. The lifetime of the call must encompass the
183
+ // argument evaluation as well.
193
184
//
194
- // To capture these patterns, we use two fields. The first,
195
- // parent, is the parent scope of a normal expression. The
196
- // second, closure_parent, is the parent scope that a closure body
197
- // ought to use. These only differ in the case of calls, where
198
- // the closure parent is the call, but the parent is the container
199
- // of the call.
200
- parent : parent ,
201
- closure_parent : parent
185
+ // The reason is that evaluation of an earlier argument could
186
+ // create a borrow which exists during the evaluation of later
187
+ // arguments. Consider this torture test, for example,
188
+ //
189
+ // fn test1(x: @mut ~int) {
190
+ // foo(&**x, *x = ~5);
191
+ // }
192
+ //
193
+ // Here, the first argument `&**x` will be a borrow of the `~int`,
194
+ // but the second argument overwrites that very value! Bad.
195
+ // (This test is borrowck-pure-scope-in-call.rs, btw)
196
+ parent : parent
202
197
} ;
203
198
204
199
// Returns true if `subscope` is equal to or is lexically nested inside
@@ -291,8 +286,7 @@ fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
291
286
record_parent ( cx, blk. node . id ) ;
292
287
293
288
// Descend.
294
- let new_cx: ctxt = { parent : some( blk. node . id ) ,
295
- closure_parent: some ( blk. node . id ) with cx} ;
289
+ let new_cx: ctxt = { parent : some( blk. node . id ) with cx} ;
296
290
visit:: visit_block ( blk, new_cx, visitor) ;
297
291
}
298
292
@@ -325,14 +319,12 @@ fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
325
319
alt expr. node {
326
320
ast:: expr_call ( * ) {
327
321
#debug[ "node %d: %s" , expr. id , pprust:: expr_to_str ( expr) ] ;
328
- let new_cx = { closure_parent : some( expr. id ) with cx} ;
322
+ let new_cx = { parent : some( expr. id ) with cx} ;
329
323
visit:: visit_expr ( expr, new_cx, visitor) ;
330
324
}
331
325
ast:: expr_alt ( subexpr, _, _) {
332
326
#debug[ "node %d: %s" , expr. id , pprust:: expr_to_str ( expr) ] ;
333
- let new_cx = { parent : some( expr. id ) ,
334
- closure_parent: some ( expr. id )
335
- with cx} ;
327
+ let new_cx = { parent : some( expr. id ) with cx} ;
336
328
visit:: visit_expr ( expr, new_cx, visitor) ;
337
329
}
338
330
ast:: expr_fn ( _, _, _, cap_clause) |
@@ -358,7 +350,7 @@ fn resolve_local(local: @ast::local, cx: ctxt, visitor: visit::vt<ctxt>) {
358
350
359
351
fn resolve_item ( item : @ast:: item , cx : ctxt , visitor : visit:: vt < ctxt > ) {
360
352
// Items create a new outer block scope as far as we're concerned.
361
- let new_cx: ctxt = { closure_parent : none , parent: none with cx} ;
353
+ let new_cx: ctxt = { parent: none with cx} ;
362
354
visit:: visit_item ( item, new_cx, visitor) ;
363
355
}
364
356
@@ -370,19 +362,18 @@ fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
370
362
visit: : fk_item_fn ( * ) | visit:: fk_method ( * ) | visit:: fk_res ( * ) |
371
363
visit:: fk_ctor ( * ) | visit:: fk_dtor( * ) {
372
364
// Top-level functions are a root scope.
373
- { parent : some( id) , closure_parent : some ( id ) with cx}
365
+ { parent : some( id) with cx}
374
366
}
375
367
376
368
visit:: fk_anon ( * ) | visit:: fk_fn_block ( * ) {
377
- // Closures use the closure_parent .
378
- { parent : cx . closure_parent with cx }
369
+ // Closures continue with the inherited scope .
370
+ cx
379
371
}
380
372
} ;
381
373
382
374
#debug[ "visiting fn with body %d. cx.parent: %? \
383
- cx.closure_parent: %? fn_cx.parent: %?",
384
- body. node . id , cx. parent ,
385
- cx. closure_parent , fn_cx. parent ] ;
375
+ fn_cx.parent: %?",
376
+ body. node . id , cx. parent , fn_cx. parent ] ;
386
377
387
378
for decl. inputs. each { |input|
388
379
cx. region_map . insert ( input. id , body. node . id ) ;
@@ -396,8 +387,7 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
396
387
let cx: ctxt = { sess: sess,
397
388
def_map: def_map,
398
389
region_map: map:: int_hash ( ) ,
399
- parent: none,
400
- closure_parent: none} ;
390
+ parent: none} ;
401
391
let visitor = visit:: mk_vt ( @{
402
392
visit_block: resolve_block,
403
393
visit_item: resolve_item,
0 commit comments