@@ -453,6 +453,43 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
453453 terminating_scopes : FxHashSet < hir:: ItemLocalId > ,
454454}
455455
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+ }
456493
457494impl < ' tcx > ScopeTree {
458495 pub fn record_scope_parent ( & mut self , child : Scope , parent : Option < Scope > ) {
@@ -612,6 +649,20 @@ impl<'tcx> ScopeTree {
612649 return true ;
613650 }
614651
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+
615666 /// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
616667 /// scope which is greater than or equal to both `scope_a` and `scope_b`.
617668 pub fn nearest_common_ancestor ( & self ,
@@ -768,6 +819,28 @@ impl<'tcx> ScopeTree {
768819 self . yield_in_scope . get ( & scope) . cloned ( )
769820 }
770821
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+
771844 /// Gives the number of expressions visited in a body.
772845 /// Used to sanity check visit_expr call count when
773846 /// calculating generator interiors.
@@ -872,9 +945,13 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
872945 record_var_lifetime ( visitor, pat. hir_id . local_id , pat. span ) ;
873946 }
874947
948+ debug ! ( "resolve_pat - pre-increment {} pat = {:?}" , visitor. expr_and_pat_count, pat) ;
949+
875950 intravisit:: walk_pat ( visitor, pat) ;
876951
877952 visitor. expr_and_pat_count += 1 ;
953+
954+ debug ! ( "resolve_pat - post-increment {} pat = {:?}" , visitor. expr_and_pat_count, pat) ;
878955}
879956
880957fn 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:
897974}
898975
899976fn 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 ) ;
901978
902979 let prev_cx = visitor. cx ;
903980 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:
9821059
9831060 visitor. expr_and_pat_count += 1 ;
9841061
1062+ debug ! ( "resolve_expr post-increment {}, expr = {:?}" , visitor. expr_and_pat_count, expr) ;
1063+
9851064 if let hir:: ExprYield ( ..) = expr. node {
9861065 // Mark this expr's scope and all parent scopes as containing `yield`.
9871066 let mut scope = Scope :: Node ( expr. hir_id . local_id ) ;
@@ -1077,12 +1156,13 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
10771156 }
10781157 }
10791158
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
10831160 if let Some ( expr) = init {
10841161 visitor. visit_expr ( expr) ;
10851162 }
1163+ if let Some ( pat) = pat {
1164+ visitor. visit_pat ( pat) ;
1165+ }
10861166
10871167 /// True if `pat` match the `P&` nonterminal:
10881168 ///
0 commit comments