@@ -9,10 +9,12 @@ use rustc_hir as hir;
9
9
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
10
10
use rustc_hir:: def_id:: DefId ;
11
11
use 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 ;
13
14
use rustc_middle:: middle:: region:: { self , YieldData } ;
14
15
use rustc_middle:: ty:: { self , Ty } ;
15
16
use rustc_span:: Span ;
17
+ use smallvec:: SmallVec ;
16
18
17
19
struct InteriorVisitor < ' a , ' tcx > {
18
20
fcx : & ' a FnCtxt < ' a , ' tcx > ,
@@ -21,6 +23,14 @@ struct InteriorVisitor<'a, 'tcx> {
21
23
expr_count : usize ,
22
24
kind : hir:: GeneratorKind ,
23
25
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 ,
24
34
}
25
35
26
36
impl < ' a , ' tcx > InteriorVisitor < ' a , ' tcx > {
@@ -30,6 +40,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
30
40
scope : Option < region:: Scope > ,
31
41
expr : Option < & ' tcx Expr < ' tcx > > ,
32
42
source_span : Span ,
43
+ guard_borrowing_from_pattern : bool ,
33
44
) {
34
45
use rustc_span:: DUMMY_SP ;
35
46
@@ -53,7 +64,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
53
64
yield_data. expr_and_pat_count, self . expr_count, source_span
54
65
) ;
55
66
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 {
57
68
Some ( yield_data)
58
69
} else {
59
70
None
@@ -134,6 +145,9 @@ pub fn resolve_interior<'a, 'tcx>(
134
145
expr_count : 0 ,
135
146
kind,
136
147
prev_unresolved_span : None ,
148
+ nested_scope_of_guards : <_ >:: default ( ) ,
149
+ current_scope_of_guards : <_ >:: default ( ) ,
150
+ arm_has_guard : false ,
137
151
} ;
138
152
intravisit:: walk_body ( & mut visitor, body) ;
139
153
@@ -210,19 +224,46 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
210
224
NestedVisitorMap :: None
211
225
}
212
226
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
+
213
249
fn visit_pat ( & mut self , pat : & ' tcx Pat < ' tcx > ) {
214
250
intravisit:: walk_pat ( self , pat) ;
215
251
216
252
self . expr_count += 1 ;
217
253
218
- if let PatKind :: Binding ( ..) = pat. kind {
254
+ if let PatKind :: Binding ( _ , id , ..) = pat. kind {
219
255
let scope = self . region_scope_tree . var_scope ( pat. hir_id . local_id ) ;
220
256
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
+ }
222
262
}
223
263
}
224
264
225
265
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
266
+ let mut guard_borrowing_from_pattern = false ;
226
267
match & expr. kind {
227
268
ExprKind :: Call ( callee, args) => match & callee. kind {
228
269
ExprKind :: Path ( qpath) => {
@@ -248,7 +289,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
248
289
}
249
290
}
250
291
_ => 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
+ }
252
304
_ => intravisit:: walk_expr ( self , expr) ,
253
305
}
254
306
@@ -259,18 +311,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
259
311
// If there are adjustments, then record the final type --
260
312
// this is the actual value that is being produced.
261
313
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 ) ;
263
315
}
264
316
265
317
// Also record the unadjusted type (which is the only type if
266
318
// there are no adjustments). The reason for this is that the
267
319
// unadjusted value is sometimes a "temporary" that would wind
268
320
// up in a MIR temporary.
269
321
//
270
- // As an example, consider an expression like `vec![].push()`.
322
+ // As an example, consider an expression like `vec![].push(x )`.
271
323
// Here, the `vec![]` would wind up MIR stored into a
272
324
// temporary variable `t` which we can borrow to invoke
273
- // `<Vec<_>>::push(&mut t)`.
325
+ // `<Vec<_>>::push(&mut t, x )`.
274
326
//
275
327
// Note that an expression can have many adjustments, and we
276
328
// are just ignoring those intermediate types. This is because
@@ -287,7 +339,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
287
339
// The type table might not have information for this expression
288
340
// if it is in a malformed scope. (#66387)
289
341
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 ) ;
291
343
} else {
292
344
self . fcx . tcx . sess . delay_span_bug ( expr. span , "no type for node" ) ;
293
345
}
0 commit comments