1
1
use crate :: build:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
2
2
use crate :: build:: matches:: { Binding , Candidate , FlatPat , MatchPair , TestCase } ;
3
3
use crate :: build:: Builder ;
4
- use rustc_data_structures:: fx:: FxIndexSet ;
4
+ use rustc_data_structures:: fx:: FxIndexMap ;
5
5
use rustc_infer:: infer:: type_variable:: TypeVariableOrigin ;
6
6
use rustc_middle:: mir:: * ;
7
7
use rustc_middle:: thir:: { self , * } ;
@@ -271,7 +271,11 @@ pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
271
271
/// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from
272
272
/// bindings inside deref patterns.
273
273
scrutinee_base : PlaceBase ,
274
- fake_borrows : FxIndexSet < Place < ' tcx > > ,
274
+ /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest
275
+ /// borrow (i.e. Deep > Shallow).
276
+ /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are
277
+ /// dereferences are also borrowed with the same of stronger borrow kind.
278
+ fake_borrows : FxIndexMap < Place < ' tcx > , FakeBorrowKind > ,
275
279
}
276
280
277
281
/// Determine the set of places that have to be stable across match guards.
@@ -314,9 +318,9 @@ pub(super) fn collect_fake_borrows<'tcx>(
314
318
candidates : & [ & mut Candidate < ' _ , ' tcx > ] ,
315
319
temp_span : Span ,
316
320
scrutinee_base : PlaceBase ,
317
- ) -> Vec < ( Place < ' tcx > , Local ) > {
321
+ ) -> Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > {
318
322
let mut collector =
319
- FakeBorrowCollector { cx, scrutinee_base, fake_borrows : FxIndexSet :: default ( ) } ;
323
+ FakeBorrowCollector { cx, scrutinee_base, fake_borrows : FxIndexMap :: default ( ) } ;
320
324
for candidate in candidates. iter ( ) {
321
325
collector. visit_candidate ( candidate) ;
322
326
}
@@ -325,40 +329,40 @@ pub(super) fn collect_fake_borrows<'tcx>(
325
329
let tcx = cx. tcx ;
326
330
fake_borrows
327
331
. iter ( )
328
- . copied ( )
329
- . map ( |matched_place| {
332
+ . map ( |( matched_place, borrow_kind) | {
330
333
let fake_borrow_deref_ty = matched_place. ty ( & cx. local_decls , tcx) . ty ;
331
334
let fake_borrow_ty =
332
335
Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , fake_borrow_deref_ty) ;
333
336
let mut fake_borrow_temp = LocalDecl :: new ( fake_borrow_ty, temp_span) ;
334
337
fake_borrow_temp. local_info = ClearCrossCrate :: Set ( Box :: new ( LocalInfo :: FakeBorrow ) ) ;
335
338
let fake_borrow_temp = cx. local_decls . push ( fake_borrow_temp) ;
336
- ( matched_place, fake_borrow_temp)
339
+ ( * matched_place, fake_borrow_temp, * borrow_kind )
337
340
} )
338
341
. collect ( )
339
342
}
340
343
341
344
impl < ' a , ' b , ' tcx > FakeBorrowCollector < ' a , ' b , ' tcx > {
342
345
// Fake borrow this place and its dereference prefixes.
343
- fn fake_borrow ( & mut self , place : Place < ' tcx > ) {
344
- let new = self . fake_borrows . insert ( place) ;
345
- if !new {
346
+ fn fake_borrow ( & mut self , place : Place < ' tcx > , kind : FakeBorrowKind ) {
347
+ if self . fake_borrows . get ( & place) . is_some_and ( |k| * k >= kind) {
346
348
return ;
347
349
}
350
+ self . fake_borrows . insert ( place, kind) ;
348
351
// Also fake borrow the prefixes of any fake borrow.
349
- self . fake_borrow_deref_prefixes ( place) ;
352
+ self . fake_borrow_deref_prefixes ( place, kind ) ;
350
353
}
351
354
352
355
// Fake borrow the prefixes of this place that are dereferences.
353
- fn fake_borrow_deref_prefixes ( & mut self , place : Place < ' tcx > ) {
356
+ fn fake_borrow_deref_prefixes ( & mut self , place : Place < ' tcx > , kind : FakeBorrowKind ) {
354
357
for ( place_ref, elem) in place. as_ref ( ) . iter_projections ( ) . rev ( ) {
355
358
if let ProjectionElem :: Deref = elem {
356
359
// Insert a shallow borrow after a deref. For other projections the borrow of
357
360
// `place_ref` will conflict with any mutation of `place.base`.
358
- let new = self . fake_borrows . insert ( place_ref. to_place ( self . cx . tcx ) ) ;
359
- if !new {
361
+ let place = place_ref. to_place ( self . cx . tcx ) ;
362
+ if self . fake_borrows . get ( & place ) . is_some_and ( |k| * k >= kind ) {
360
363
return ;
361
364
}
365
+ self . fake_borrows . insert ( place, kind) ;
362
366
}
363
367
}
364
368
}
@@ -399,15 +403,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
399
403
// // UB because we reached the unreachable.
400
404
// }
401
405
// ```
402
- // FIXME(deref_patterns): Hence we fake borrow using a non-shallow borrow.
406
+ // Hence we fake borrow using a deep borrow.
403
407
if let Some ( place) = match_pair. place {
404
- // FIXME(deref_patterns): use a non-shallow borrow.
405
- self . fake_borrow ( place) ;
408
+ self . fake_borrow ( place, FakeBorrowKind :: Deep ) ;
406
409
}
407
410
} else {
408
411
// Insert a Shallow borrow of any place that is switched on.
409
412
if let Some ( place) = match_pair. place {
410
- self . fake_borrow ( place) ;
413
+ self . fake_borrow ( place, FakeBorrowKind :: Shallow ) ;
411
414
}
412
415
413
416
for subpair in & match_pair. subpairs {
@@ -447,7 +450,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
447
450
// _ if { u = true; false } => (),
448
451
// x => (),
449
452
// }
450
- self . fake_borrow_deref_prefixes ( * source) ;
453
+ self . fake_borrow_deref_prefixes ( * source, FakeBorrowKind :: Shallow ) ;
451
454
}
452
455
}
453
456
0 commit comments