@@ -453,6 +453,43 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
453
453
terminating_scopes : FxHashSet < hir:: ItemLocalId > ,
454
454
}
455
455
456
+ struct ExprLocatorVisitor {
457
+ id : ast:: NodeId ,
458
+ result : Option < usize > ,
459
+ expr_and_pat_count : usize ,
460
+ }
461
+
462
+ // This visitor has to have the same visit_expr calls as RegionResolutionVisitor
463
+ // since `expr_count` is compared against the results there.
464
+ impl < ' tcx > Visitor < ' tcx > for ExprLocatorVisitor {
465
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' tcx > {
466
+ NestedVisitorMap :: None
467
+ }
468
+
469
+ fn visit_pat ( & mut self , pat : & ' tcx Pat ) {
470
+ self . expr_and_pat_count += 1 ;
471
+
472
+ intravisit:: walk_pat ( self , pat) ;
473
+ }
474
+
475
+ fn visit_expr ( & mut self , expr : & ' tcx Expr ) {
476
+ debug ! ( "ExprLocatorVisitor - pre-increment {} expr = {:?}" ,
477
+ self . expr_and_pat_count,
478
+ expr) ;
479
+
480
+ intravisit:: walk_expr ( self , expr) ;
481
+
482
+ self . expr_and_pat_count += 1 ;
483
+
484
+ debug ! ( "ExprLocatorVisitor - post-increment {} expr = {:?}" ,
485
+ self . expr_and_pat_count,
486
+ expr) ;
487
+
488
+ if expr. id == self . id {
489
+ self . result = Some ( self . expr_and_pat_count ) ;
490
+ }
491
+ }
492
+ }
456
493
457
494
impl < ' tcx > ScopeTree {
458
495
pub fn record_scope_parent ( & mut self , child : Scope , parent : Option < Scope > ) {
@@ -612,6 +649,20 @@ impl<'tcx> ScopeTree {
612
649
return true ;
613
650
}
614
651
652
+ /// Returns the id of the innermost containing body
653
+ pub fn containing_body ( & self , mut scope : Scope ) -> Option < hir:: ItemLocalId > {
654
+ loop {
655
+ if let ScopeData :: CallSite ( id) = scope. data ( ) {
656
+ return Some ( id) ;
657
+ }
658
+
659
+ match self . opt_encl_scope ( scope) {
660
+ None => return None ,
661
+ Some ( parent) => scope = parent,
662
+ }
663
+ }
664
+ }
665
+
615
666
/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
616
667
/// scope which is greater than or equal to both `scope_a` and `scope_b`.
617
668
pub fn nearest_common_ancestor ( & self ,
@@ -768,6 +819,28 @@ impl<'tcx> ScopeTree {
768
819
self . yield_in_scope . get ( & scope) . cloned ( )
769
820
}
770
821
822
+ /// Checks whether the given scope contains a `yield` and if that yield could execute
823
+ /// after `expr`. If so, it returns the span of that `yield`.
824
+ /// `scope` must be inside the body.
825
+ pub fn yield_in_scope_for_expr ( & self ,
826
+ scope : Scope ,
827
+ expr : ast:: NodeId ,
828
+ body : & ' tcx hir:: Body ) -> Option < Span > {
829
+ self . yield_in_scope ( scope) . and_then ( |( span, count) | {
830
+ let mut visitor = ExprLocatorVisitor {
831
+ id : expr,
832
+ result : None ,
833
+ expr_and_pat_count : 0 ,
834
+ } ;
835
+ visitor. visit_body ( body) ;
836
+ if count >= visitor. result . unwrap ( ) {
837
+ Some ( span)
838
+ } else {
839
+ None
840
+ }
841
+ } )
842
+ }
843
+
771
844
/// Gives the number of expressions visited in a body.
772
845
/// Used to sanity check visit_expr call count when
773
846
/// calculating generator interiors.
@@ -872,9 +945,13 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
872
945
record_var_lifetime ( visitor, pat. hir_id . local_id , pat. span ) ;
873
946
}
874
947
948
+ debug ! ( "resolve_pat - pre-increment {} pat = {:?}" , visitor. expr_and_pat_count, pat) ;
949
+
875
950
intravisit:: walk_pat ( visitor, pat) ;
876
951
877
952
visitor. expr_and_pat_count += 1 ;
953
+
954
+ debug ! ( "resolve_pat - post-increment {} pat = {:?}" , visitor. expr_and_pat_count, pat) ;
878
955
}
879
956
880
957
fn resolve_stmt < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > , stmt : & ' tcx hir:: Stmt ) {
@@ -897,7 +974,7 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt:
897
974
}
898
975
899
976
fn resolve_expr < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > , expr : & ' tcx hir:: Expr ) {
900
- debug ! ( "resolve_expr( expr.id= {:?}) " , expr . id ) ;
977
+ debug ! ( "resolve_expr - pre-increment {} expr = {:?}" , visitor . expr_and_pat_count , expr ) ;
901
978
902
979
let prev_cx = visitor. cx ;
903
980
visitor. enter_node_scope_with_dtor ( expr. hir_id . local_id ) ;
@@ -982,6 +1059,8 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
982
1059
983
1060
visitor. expr_and_pat_count += 1 ;
984
1061
1062
+ debug ! ( "resolve_expr post-increment {}, expr = {:?}" , visitor. expr_and_pat_count, expr) ;
1063
+
985
1064
if let hir:: ExprYield ( ..) = expr. node {
986
1065
// Mark this expr's scope and all parent scopes as containing `yield`.
987
1066
let mut scope = Scope :: Node ( expr. hir_id . local_id ) ;
@@ -1077,12 +1156,13 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
1077
1156
}
1078
1157
}
1079
1158
1080
- if let Some ( pat) = pat {
1081
- visitor. visit_pat ( pat) ;
1082
- }
1159
+ // Make sure we visit the initializer first, so expr_and_pat_count remains correct
1083
1160
if let Some ( expr) = init {
1084
1161
visitor. visit_expr ( expr) ;
1085
1162
}
1163
+ if let Some ( pat) = pat {
1164
+ visitor. visit_pat ( pat) ;
1165
+ }
1086
1166
1087
1167
/// True if `pat` match the `P&` nonterminal:
1088
1168
///
0 commit comments