@@ -259,8 +259,37 @@ pub struct ScopeTree {
259259 /// lower than theirs, and therefore don't need to be suspended
260260 /// at yield-points at these indexes.
261261 ///
262- /// Let's show that: let `D` be our binding/temporary and `U` be our
263- /// other HIR node, with `HIR-postorder(U) < HIR-postorder(D)`.
262+ /// For an example, suppose we have some code such as:
263+ /// ```rust,ignore (example)
264+ /// foo(f(), yield y, bar(g()))
265+ /// ```
266+ ///
267+ /// With the HIR tree (calls numbered for expository purposes)
268+ /// ```
269+ /// Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))])
270+ /// ```
271+ ///
272+ /// Obviously, the result of `f()` was created before the yield
273+ /// (and therefore needs to be kept valid over the yield) while
274+ /// the result of `g()` occurs after the yield (and therefore
275+ /// doesn't). If we want to infer that, we can look at the
276+ /// postorder traversal:
277+ /// ```
278+ /// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0
279+ /// ```
280+ ///
281+ /// In which we can easily see that `Call#1` occurs before the yield,
282+ /// and `Call#3` after it.
283+ ///
284+ /// To see that this method works, consider:
285+ ///
286+ /// Let `D` be our binding/temporary and `U` be our other HIR node, with
287+ /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be
288+ /// the yield and D would be one of the calls). Let's show that
289+ /// `D` is storage-dead at `U`.
290+ ///
291+ /// Remember that storage-live/storage-dead refers to the state of
292+ /// the *storage*, and does not consider moves/drop flags.
264293 ///
265294 /// Then:
266295 /// 1. From the ordering guarantee of HIR visitors (see
@@ -272,17 +301,26 @@ pub struct ScopeTree {
272301 /// or always storage-dead. This is what is being guaranteed
273302 /// by `terminating_scopes` including all blocks where the
274303 /// count of executions is not guaranteed.
275- /// 4. By `2.` and `3.`, `D` is *statically* dead at `U`,
304+ /// 4. By `2.` and `3.`, `D` is *statically* storage- dead at `U`,
276305 /// QED.
277306 ///
278307 /// I don't think this property relies on `3.` in an essential way - it
279308 /// is probably still correct even if we have "unrestricted" terminating
280309 /// scopes. However, why use the complicated proof when a simple one
281310 /// works?
311+ ///
312+ /// A subtle thing: `box` expressions, such as `box (&x, yield 2, &y)`. It
313+ /// might seem that a `box` expression creates a `Box<T>` temporary
314+ /// when it *starts* executing, at `HIR-preorder(BOX-EXPR)`. That might
315+ /// be true in the MIR desugaring, but it is not important in the semantics.
316+ ///
317+ /// The reason is that semantically, until the `box` expression returns,
318+ /// the values are still owned by their containing expressions. So
319+ /// we'll see that `&x`.
282320 yield_in_scope : FxHashMap < Scope , ( Span , usize ) > ,
283321
284- /// The number of visit_expr calls done in the body.
285- /// Used to sanity check visit_expr call count when
322+ /// The number of visit_expr and visit_pat calls done in the body.
323+ /// Used to sanity check visit_expr/visit_pat call count when
286324 /// calculating geneartor interiors.
287325 body_expr_count : FxHashMap < hir:: BodyId , usize > ,
288326}
@@ -307,8 +345,8 @@ pub struct Context {
307345struct RegionResolutionVisitor < ' a , ' tcx : ' a > {
308346 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
309347
310- // The number of expressions visited in the current body
311- expr_count : usize ,
348+ // The number of expressions and patterns visited in the current body
349+ expr_and_pat_count : usize ,
312350
313351 // Generated scope tree:
314352 scope_tree : ScopeTree ,
@@ -758,6 +796,8 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
758796 }
759797
760798 intravisit:: walk_pat ( visitor, pat) ;
799+
800+ visitor. expr_and_pat_count += 1 ;
761801}
762802
763803fn resolve_stmt < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > , stmt : & ' tcx hir:: Stmt ) {
@@ -863,14 +903,14 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
863903 _ => intravisit:: walk_expr ( visitor, expr)
864904 }
865905
866- visitor. expr_count += 1 ;
906+ visitor. expr_and_pat_count += 1 ;
867907
868908 if let hir:: ExprYield ( ..) = expr. node {
869909 // Mark this expr's scope and all parent scopes as containing `yield`.
870910 let mut scope = Scope :: Node ( expr. hir_id . local_id ) ;
871911 loop {
872912 visitor. scope_tree . yield_in_scope . insert ( scope,
873- ( expr. span , visitor. expr_count ) ) ;
913+ ( expr. span , visitor. expr_and_pat_count ) ) ;
874914
875915 // Keep traversing up while we can.
876916 match visitor. scope_tree . parent_map . get ( & scope) {
@@ -1160,7 +1200,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11601200 body_id,
11611201 self . cx. parent) ;
11621202
1163- let outer_ec = mem:: replace ( & mut self . expr_count , 0 ) ;
1203+ let outer_ec = mem:: replace ( & mut self . expr_and_pat_count , 0 ) ;
11641204 let outer_cx = self . cx ;
11651205 let outer_ts = mem:: replace ( & mut self . terminating_scopes , FxHashSet ( ) ) ;
11661206 self . terminating_scopes . insert ( body. value . hir_id . local_id ) ;
@@ -1207,11 +1247,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
12071247 }
12081248
12091249 if body. is_generator {
1210- self . scope_tree . body_expr_count . insert ( body_id, self . expr_count ) ;
1250+ self . scope_tree . body_expr_count . insert ( body_id, self . expr_and_pat_count ) ;
12111251 }
12121252
12131253 // Restore context we had at the start.
1214- self . expr_count = outer_ec;
1254+ self . expr_and_pat_count = outer_ec;
12151255 self . cx = outer_cx;
12161256 self . terminating_scopes = outer_ts;
12171257 }
@@ -1246,7 +1286,7 @@ fn region_scope_tree<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
12461286 let mut visitor = RegionResolutionVisitor {
12471287 tcx,
12481288 scope_tree : ScopeTree :: default ( ) ,
1249- expr_count : 0 ,
1289+ expr_and_pat_count : 0 ,
12501290 cx : Context {
12511291 root_id : None ,
12521292 parent : None ,
0 commit comments