@@ -259,8 +259,37 @@ pub struct ScopeTree {
259
259
/// lower than theirs, and therefore don't need to be suspended
260
260
/// at yield-points at these indexes.
261
261
///
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.
264
293
///
265
294
/// Then:
266
295
/// 1. From the ordering guarantee of HIR visitors (see
@@ -272,17 +301,26 @@ pub struct ScopeTree {
272
301
/// or always storage-dead. This is what is being guaranteed
273
302
/// by `terminating_scopes` including all blocks where the
274
303
/// 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`,
276
305
/// QED.
277
306
///
278
307
/// I don't think this property relies on `3.` in an essential way - it
279
308
/// is probably still correct even if we have "unrestricted" terminating
280
309
/// scopes. However, why use the complicated proof when a simple one
281
310
/// 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`.
282
320
yield_in_scope : FxHashMap < Scope , ( Span , usize ) > ,
283
321
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
286
324
/// calculating geneartor interiors.
287
325
body_expr_count : FxHashMap < hir:: BodyId , usize > ,
288
326
}
@@ -307,8 +345,8 @@ pub struct Context {
307
345
struct RegionResolutionVisitor < ' a , ' tcx : ' a > {
308
346
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
309
347
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 ,
312
350
313
351
// Generated scope tree:
314
352
scope_tree : ScopeTree ,
@@ -758,6 +796,8 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
758
796
}
759
797
760
798
intravisit:: walk_pat ( visitor, pat) ;
799
+
800
+ visitor. expr_and_pat_count += 1 ;
761
801
}
762
802
763
803
fn 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:
863
903
_ => intravisit:: walk_expr ( visitor, expr)
864
904
}
865
905
866
- visitor. expr_count += 1 ;
906
+ visitor. expr_and_pat_count += 1 ;
867
907
868
908
if let hir:: ExprYield ( ..) = expr. node {
869
909
// Mark this expr's scope and all parent scopes as containing `yield`.
870
910
let mut scope = Scope :: Node ( expr. hir_id . local_id ) ;
871
911
loop {
872
912
visitor. scope_tree . yield_in_scope . insert ( scope,
873
- ( expr. span , visitor. expr_count ) ) ;
913
+ ( expr. span , visitor. expr_and_pat_count ) ) ;
874
914
875
915
// Keep traversing up while we can.
876
916
match visitor. scope_tree . parent_map . get ( & scope) {
@@ -1160,7 +1200,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
1160
1200
body_id,
1161
1201
self . cx. parent) ;
1162
1202
1163
- let outer_ec = mem:: replace ( & mut self . expr_count , 0 ) ;
1203
+ let outer_ec = mem:: replace ( & mut self . expr_and_pat_count , 0 ) ;
1164
1204
let outer_cx = self . cx ;
1165
1205
let outer_ts = mem:: replace ( & mut self . terminating_scopes , FxHashSet ( ) ) ;
1166
1206
self . terminating_scopes . insert ( body. value . hir_id . local_id ) ;
@@ -1207,11 +1247,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
1207
1247
}
1208
1248
1209
1249
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 ) ;
1211
1251
}
1212
1252
1213
1253
// Restore context we had at the start.
1214
- self . expr_count = outer_ec;
1254
+ self . expr_and_pat_count = outer_ec;
1215
1255
self . cx = outer_cx;
1216
1256
self . terminating_scopes = outer_ts;
1217
1257
}
@@ -1246,7 +1286,7 @@ fn region_scope_tree<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
1246
1286
let mut visitor = RegionResolutionVisitor {
1247
1287
tcx,
1248
1288
scope_tree : ScopeTree :: default ( ) ,
1249
- expr_count : 0 ,
1289
+ expr_and_pat_count : 0 ,
1250
1290
cx : Context {
1251
1291
root_id : None ,
1252
1292
parent : None ,
0 commit comments