@@ -206,50 +206,64 @@ impl CodeExtent {
206206}
207207
208208/// The region maps encode information about region relationships.
209- ///
210- /// - `scope_map` maps from a scope id to the enclosing scope id; this is
211- /// usually corresponding to the lexical nesting, though in the case of
212- /// closures the parent scope is the innermost conditional expression or repeating
213- /// block. (Note that the enclosing scope id for the block
214- /// associated with a closure is the closure itself.)
215- ///
216- /// - `var_map` maps from a variable or binding id to the block in which
217- /// that variable is declared.
218- ///
219- /// - `free_region_map` maps from a free region `a` to a list of free
220- /// regions `bs` such that `a <= b for all b in bs`
221- /// - the free region map is populated during type check as we check
222- /// each function. See the function `relate_free_regions` for
223- /// more information.
224- ///
225- /// - `rvalue_scopes` includes entries for those expressions whose cleanup
226- /// scope is larger than the default. The map goes from the expression
227- /// id to the cleanup scope id. For rvalues not present in this table,
228- /// the appropriate cleanup scope is the innermost enclosing statement,
229- /// conditional expression, or repeating block (see `terminating_scopes`).
230- ///
231- /// - `terminating_scopes` is a set containing the ids of each statement,
232- /// or conditional/repeating expression. These scopes are calling "terminating
233- /// scopes" because, when attempting to find the scope of a temporary, by
234- /// default we search up the enclosing scopes until we encounter the
235- /// terminating scope. A conditional/repeating
236- /// expression is one which is not guaranteed to execute exactly once
237- /// upon entering the parent scope. This could be because the expression
238- /// only executes conditionally, such as the expression `b` in `a && b`,
239- /// or because the expression may execute many times, such as a loop
240- /// body. The reason that we distinguish such expressions is that, upon
241- /// exiting the parent scope, we cannot statically know how many times
242- /// the expression executed, and thus if the expression creates
243- /// temporaries we cannot know statically how many such temporaries we
244- /// would have to cleanup. Therefore we ensure that the temporaries never
245- /// outlast the conditional/repeating expression, preventing the need
246- /// for dynamic checks and/or arbitrary amounts of stack space.
247209pub struct RegionMaps {
210+ /// `scope_map` maps from a scope id to the enclosing scope id;
211+ /// this is usually corresponding to the lexical nesting, though
212+ /// in the case of closures the parent scope is the innermost
213+ /// conditional expression or repeating block. (Note that the
214+ /// enclosing scope id for the block associated with a closure is
215+ /// the closure itself.)
248216 scope_map : RefCell < FnvHashMap < CodeExtent , CodeExtent > > ,
217+
218+ /// `var_map` maps from a variable or binding id to the block in
219+ /// which that variable is declared.
249220 var_map : RefCell < NodeMap < CodeExtent > > ,
221+
222+ /// `free_region_map` maps from a free region `a` to a list of
223+ /// free regions `bs` such that `a <= b for all b in bs`
224+ ///
225+ /// NB. the free region map is populated during type check as we
226+ /// check each function. See the function `relate_free_regions`
227+ /// for more information.
250228 free_region_map : RefCell < FnvHashMap < FreeRegion , Vec < FreeRegion > > > ,
229+
230+ /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
231+ /// larger than the default. The map goes from the expression id
232+ /// to the cleanup scope id. For rvalues not present in this
233+ /// table, the appropriate cleanup scope is the innermost
234+ /// enclosing statement, conditional expression, or repeating
235+ /// block (see `terminating_scopes`).
251236 rvalue_scopes : RefCell < NodeMap < CodeExtent > > ,
237+
238+ /// `terminating_scopes` is a set containing the ids of each
239+ /// statement, or conditional/repeating expression. These scopes
240+ /// are calling "terminating scopes" because, when attempting to
241+ /// find the scope of a temporary, by default we search up the
242+ /// enclosing scopes until we encounter the terminating scope. A
243+ /// conditional/repeating expression is one which is not
244+ /// guaranteed to execute exactly once upon entering the parent
245+ /// scope. This could be because the expression only executes
246+ /// conditionally, such as the expression `b` in `a && b`, or
247+ /// because the expression may execute many times, such as a loop
248+ /// body. The reason that we distinguish such expressions is that,
249+ /// upon exiting the parent scope, we cannot statically know how
250+ /// many times the expression executed, and thus if the expression
251+ /// creates temporaries we cannot know statically how many such
252+ /// temporaries we would have to cleanup. Therefore we ensure that
253+ /// the temporaries never outlast the conditional/repeating
254+ /// expression, preventing the need for dynamic checks and/or
255+ /// arbitrary amounts of stack space.
252256 terminating_scopes : RefCell < FnvHashSet < CodeExtent > > ,
257+
258+ /// Encodes the hierarchy of fn bodies. Every fn body (including
259+ /// closures) forms its own distinct region hierarchy, rooted in
260+ /// the block that is the fn body. This map points from the id of
261+ /// that root block to the id of the root block for the enclosing
262+ /// fn, if any. Thus the map structures the fn bodies into a
263+ /// hierarchy based on their lexical mapping. This is used to
264+ /// handle the relationships between regions in a fn and in a
265+ /// closure defined by that fn.
266+ fn_tree : RefCell < NodeMap < ast:: NodeId > > ,
253267}
254268
255269/// Carries the node id for the innermost block or match expression,
@@ -320,6 +334,12 @@ impl InnermostEnclosingExpr {
320334
321335#[ derive( Debug , Copy ) ]
322336pub struct Context {
337+ /// the root of the current region tree. This is typically the id
338+ /// of the innermost fn body. Each fn forms its own disjoint tree
339+ /// in the region hierarchy. These fn bodies are themselves
340+ /// arranged into a tree.
341+ root_id : Option < ast:: NodeId > ,
342+
323343 /// the scope that contains any new variables declared
324344 var_parent : InnermostDeclaringBlock ,
325345
@@ -381,19 +401,29 @@ impl RegionMaps {
381401 self . free_region_map . borrow_mut ( ) . insert ( sub, vec ! ( sup) ) ;
382402 }
383403
384- pub fn record_encl_scope ( & self , sub : CodeExtent , sup : CodeExtent ) {
404+ /// Records that `sub_fn` is defined within `sup_fn`. These ids
405+ /// should be the id of the block that is the fn body, which is
406+ /// also the root of the region hierarchy for that fn.
407+ fn record_fn_parent ( & self , sub_fn : ast:: NodeId , sup_fn : ast:: NodeId ) {
408+ debug ! ( "record_fn_parent(sub_fn={:?}, sup_fn={:?})" , sub_fn, sup_fn) ;
409+ assert ! ( sub_fn != sup_fn) ;
410+ let previous = self . fn_tree . borrow_mut ( ) . insert ( sub_fn, sup_fn) ;
411+ assert ! ( previous. is_none( ) ) ;
412+ }
413+
414+ fn record_encl_scope ( & self , sub : CodeExtent , sup : CodeExtent ) {
385415 debug ! ( "record_encl_scope(sub={:?}, sup={:?})" , sub, sup) ;
386416 assert ! ( sub != sup) ;
387417 self . scope_map . borrow_mut ( ) . insert ( sub, sup) ;
388418 }
389419
390- pub fn record_var_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
420+ fn record_var_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
391421 debug ! ( "record_var_scope(sub={:?}, sup={:?})" , var, lifetime) ;
392422 assert ! ( var != lifetime. node_id( ) ) ;
393423 self . var_map . borrow_mut ( ) . insert ( var, lifetime) ;
394424 }
395425
396- pub fn record_rvalue_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
426+ fn record_rvalue_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
397427 debug ! ( "record_rvalue_scope(sub={:?}, sup={:?})" , var, lifetime) ;
398428 assert ! ( var != lifetime. node_id( ) ) ;
399429 self . rvalue_scopes . borrow_mut ( ) . insert ( var, lifetime) ;
@@ -402,7 +432,7 @@ impl RegionMaps {
402432 /// Records that a scope is a TERMINATING SCOPE. Whenever we create automatic temporaries --
403433 /// e.g. by an expression like `a().f` -- they will be freed within the innermost terminating
404434 /// scope.
405- pub fn mark_as_terminating_scope ( & self , scope_id : CodeExtent ) {
435+ fn mark_as_terminating_scope ( & self , scope_id : CodeExtent ) {
406436 debug ! ( "record_terminating_scope(scope_id={:?})" , scope_id) ;
407437 self . terminating_scopes . borrow_mut ( ) . insert ( scope_id) ;
408438 }
@@ -684,6 +714,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
684714 // itself has returned.
685715
686716 visitor. cx = Context {
717+ root_id : prev_cx. root_id ,
687718 var_parent : InnermostDeclaringBlock :: Block ( blk. id ) ,
688719 parent : InnermostEnclosingExpr :: Some ( blk. id ) ,
689720 } ;
@@ -710,6 +741,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
710741 record_superlifetime (
711742 visitor, declaring. to_code_extent ( ) , statement. span ) ;
712743 visitor. cx = Context {
744+ root_id : prev_cx. root_id ,
713745 var_parent : InnermostDeclaringBlock :: Statement ( declaring) ,
714746 parent : InnermostEnclosingExpr :: Statement ( declaring) ,
715747 } ;
@@ -1103,6 +1135,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &ast::Item) {
11031135 // Items create a new outer block scope as far as we're concerned.
11041136 let prev_cx = visitor. cx ;
11051137 visitor. cx = Context {
1138+ root_id : None ,
11061139 var_parent : InnermostDeclaringBlock :: None ,
11071140 parent : InnermostEnclosingExpr :: None
11081141 } ;
@@ -1127,14 +1160,21 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
11271160
11281161 let body_scope = CodeExtent :: from_node_id ( body. id ) ;
11291162 visitor. region_maps . mark_as_terminating_scope ( body_scope) ;
1163+
11301164 let dtor_scope = CodeExtent :: DestructionScope ( body. id ) ;
11311165 visitor. region_maps . record_encl_scope ( body_scope, dtor_scope) ;
1166+
11321167 record_superlifetime ( visitor, dtor_scope, body. span ) ;
11331168
1169+ if let Some ( root_id) = visitor. cx . root_id {
1170+ visitor. region_maps . record_fn_parent ( body. id , root_id) ;
1171+ }
1172+
11341173 let outer_cx = visitor. cx ;
11351174
11361175 // The arguments and `self` are parented to the body of the fn.
11371176 visitor. cx = Context {
1177+ root_id : Some ( body. id ) ,
11381178 parent : InnermostEnclosingExpr :: Some ( body. id ) ,
11391179 var_parent : InnermostDeclaringBlock :: Block ( body. id )
11401180 } ;
@@ -1145,11 +1185,11 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
11451185 match fk {
11461186 visit:: FkItemFn ( ..) | visit:: FkMethod ( ..) => {
11471187 visitor. cx = Context {
1188+ root_id : Some ( body. id ) ,
11481189 parent : InnermostEnclosingExpr :: None ,
11491190 var_parent : InnermostDeclaringBlock :: None
11501191 } ;
11511192 visitor. visit_block ( body) ;
1152- visitor. cx = outer_cx;
11531193 }
11541194 visit:: FkFnBlock ( ..) => {
11551195 // FIXME(#3696) -- at present we are place the closure body
@@ -1159,10 +1199,16 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
11591199 // but the correct fix is a bit subtle, and I am also not sure
11601200 // that the present approach is unsound -- it may not permit
11611201 // any illegal programs. See issue for more details.
1162- visitor. cx = outer_cx;
1202+ visitor. cx = Context {
1203+ root_id : Some ( body. id ) ,
1204+ ..outer_cx
1205+ } ;
11631206 visitor. visit_block ( body) ;
11641207 }
11651208 }
1209+
1210+ // Restore context we had at the start.
1211+ visitor. cx = outer_cx;
11661212}
11671213
11681214impl < ' a , ' v > Visitor < ' v > for RegionResolutionVisitor < ' a > {
@@ -1203,12 +1249,14 @@ pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps {
12031249 free_region_map : RefCell :: new ( FnvHashMap ( ) ) ,
12041250 rvalue_scopes : RefCell :: new ( NodeMap ( ) ) ,
12051251 terminating_scopes : RefCell :: new ( FnvHashSet ( ) ) ,
1252+ fn_tree : RefCell :: new ( NodeMap ( ) ) ,
12061253 } ;
12071254 {
12081255 let mut visitor = RegionResolutionVisitor {
12091256 sess : sess,
12101257 region_maps : & maps,
12111258 cx : Context {
1259+ root_id : None ,
12121260 parent : InnermostEnclosingExpr :: None ,
12131261 var_parent : InnermostDeclaringBlock :: None ,
12141262 }
@@ -1225,6 +1273,7 @@ pub fn resolve_inlined_item(sess: &Session,
12251273 sess : sess,
12261274 region_maps : region_maps,
12271275 cx : Context {
1276+ root_id : None ,
12281277 parent : InnermostEnclosingExpr :: None ,
12291278 var_parent : InnermostDeclaringBlock :: None
12301279 }
0 commit comments