@@ -9,10 +9,12 @@ use rustc_hir as hir;
99use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
1010use rustc_hir:: def_id:: DefId ;
1111use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
12- use rustc_hir:: { Expr , ExprKind , Pat , PatKind } ;
12+ use rustc_hir:: { Expr , ExprKind , Pat , PatKind , Arm , Guard , HirId } ;
13+ use rustc_hir:: hir_id:: HirIdSet ;
1314use rustc_middle:: middle:: region:: { self , YieldData } ;
1415use rustc_middle:: ty:: { self , Ty } ;
1516use rustc_span:: Span ;
17+ use smallvec:: SmallVec ;
1618
1719struct InteriorVisitor < ' a , ' tcx > {
1820 fcx : & ' a FnCtxt < ' a , ' tcx > ,
@@ -21,6 +23,14 @@ struct InteriorVisitor<'a, 'tcx> {
2123 expr_count : usize ,
2224 kind : hir:: GeneratorKind ,
2325 prev_unresolved_span : Option < Span > ,
26+ /// Match arm guards have temporary borrows from the pattern bindings.
27+ /// In case there is a yield point in a guard with a reference to such bindings,
28+ /// such borrows can span across this yield point.
29+ /// As such, we need to track these borrows and record them despite of the fact
30+ /// that they may succeed the said yield point in the post-order.
31+ nested_scope_of_guards : SmallVec < [ SmallVec < [ HirId ; 4 ] > ; 4 ] > ,
32+ current_scope_of_guards : HirIdSet ,
33+ arm_has_guard : bool ,
2434}
2535
2636impl < ' a , ' tcx > InteriorVisitor < ' a , ' tcx > {
@@ -30,6 +40,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
3040 scope : Option < region:: Scope > ,
3141 expr : Option < & ' tcx Expr < ' tcx > > ,
3242 source_span : Span ,
43+ guard_borrowing_from_pattern : bool ,
3344 ) {
3445 use rustc_span:: DUMMY_SP ;
3546
@@ -53,7 +64,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
5364 yield_data. expr_and_pat_count, self . expr_count, source_span
5465 ) ;
5566
56- if yield_data. expr_and_pat_count >= self . expr_count {
67+ if guard_borrowing_from_pattern || yield_data. expr_and_pat_count >= self . expr_count {
5768 Some ( yield_data)
5869 } else {
5970 None
@@ -134,6 +145,9 @@ pub fn resolve_interior<'a, 'tcx>(
134145 expr_count : 0 ,
135146 kind,
136147 prev_unresolved_span : None ,
148+ nested_scope_of_guards : <_ >:: default ( ) ,
149+ current_scope_of_guards : <_ >:: default ( ) ,
150+ arm_has_guard : false ,
137151 } ;
138152 intravisit:: walk_body ( & mut visitor, body) ;
139153
@@ -210,19 +224,46 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
210224 NestedVisitorMap :: None
211225 }
212226
227+ fn visit_arm ( & mut self , arm : & ' tcx Arm < ' tcx > ) {
228+ if arm. guard . is_some ( ) {
229+ self . nested_scope_of_guards . push ( <_ >:: default ( ) ) ;
230+ self . arm_has_guard = true ;
231+ }
232+ self . visit_pat ( & arm. pat ) ;
233+ if let Some ( ref g) = arm. guard {
234+ match g {
235+ Guard :: If ( ref e) => {
236+ self . visit_expr ( e) ;
237+ }
238+ }
239+ let mut scope_var_ids =
240+ self . nested_scope_of_guards . pop ( ) . expect ( "should have pushed at least one earlier" ) ;
241+ for var_id in scope_var_ids. drain ( ..) {
242+ assert ! ( self . current_scope_of_guards. remove( & var_id) , "variable should be placed in scope earlier" ) ;
243+ }
244+ self . arm_has_guard = false ;
245+ }
246+ self . visit_expr ( & arm. body ) ;
247+ }
248+
213249 fn visit_pat ( & mut self , pat : & ' tcx Pat < ' tcx > ) {
214250 intravisit:: walk_pat ( self , pat) ;
215251
216252 self . expr_count += 1 ;
217253
218- if let PatKind :: Binding ( ..) = pat. kind {
254+ if let PatKind :: Binding ( _ , id , ..) = pat. kind {
219255 let scope = self . region_scope_tree . var_scope ( pat. hir_id . local_id ) ;
220256 let ty = self . fcx . typeck_results . borrow ( ) . pat_ty ( pat) ;
221- self . record ( ty, Some ( scope) , None , pat. span ) ;
257+ self . record ( ty, Some ( scope) , None , pat. span , false ) ;
258+ if self . arm_has_guard {
259+ self . nested_scope_of_guards . as_mut_slice ( ) . last_mut ( ) . unwrap ( ) . push ( id) ;
260+ self . current_scope_of_guards . insert ( id) ;
261+ }
222262 }
223263 }
224264
225265 fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
266+ let mut guard_borrowing_from_pattern = false ;
226267 match & expr. kind {
227268 ExprKind :: Call ( callee, args) => match & callee. kind {
228269 ExprKind :: Path ( qpath) => {
@@ -248,7 +289,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
248289 }
249290 }
250291 _ => intravisit:: walk_expr ( self , expr) ,
251- } ,
292+ }
293+ ExprKind :: Path ( qpath) => {
294+ intravisit:: walk_expr ( self , expr) ;
295+ let res = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, expr. hir_id ) ;
296+ match res {
297+ Res :: Local ( id) if self . current_scope_of_guards . contains ( & id) => {
298+ debug ! ( "a borrow in guard from pattern local is detected" ) ;
299+ guard_borrowing_from_pattern = true ;
300+ }
301+ _ => { }
302+ }
303+ }
252304 _ => intravisit:: walk_expr ( self , expr) ,
253305 }
254306
@@ -259,18 +311,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
259311 // If there are adjustments, then record the final type --
260312 // this is the actual value that is being produced.
261313 if let Some ( adjusted_ty) = self . fcx . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( expr) {
262- self . record ( adjusted_ty, scope, Some ( expr) , expr. span ) ;
314+ self . record ( adjusted_ty, scope, Some ( expr) , expr. span , guard_borrowing_from_pattern ) ;
263315 }
264316
265317 // Also record the unadjusted type (which is the only type if
266318 // there are no adjustments). The reason for this is that the
267319 // unadjusted value is sometimes a "temporary" that would wind
268320 // up in a MIR temporary.
269321 //
270- // As an example, consider an expression like `vec![].push()`.
322+ // As an example, consider an expression like `vec![].push(x )`.
271323 // Here, the `vec![]` would wind up MIR stored into a
272324 // temporary variable `t` which we can borrow to invoke
273- // `<Vec<_>>::push(&mut t)`.
325+ // `<Vec<_>>::push(&mut t, x )`.
274326 //
275327 // Note that an expression can have many adjustments, and we
276328 // are just ignoring those intermediate types. This is because
@@ -287,7 +339,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
287339 // The type table might not have information for this expression
288340 // if it is in a malformed scope. (#66387)
289341 if let Some ( ty) = self . fcx . typeck_results . borrow ( ) . expr_ty_opt ( expr) {
290- self . record ( ty, scope, Some ( expr) , expr. span ) ;
342+ self . record ( ty, scope, Some ( expr) , expr. span , guard_borrowing_from_pattern ) ;
291343 } else {
292344 self . fcx . tcx . sess . delay_span_bug ( expr. span , "no type for node" ) ;
293345 }
0 commit comments