11use crate :: build:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
22use crate :: build:: matches:: { Binding , Candidate , FlatPat , MatchPair , TestCase } ;
33use crate :: build:: Builder ;
4- use rustc_data_structures:: fx:: FxIndexSet ;
4+ use rustc_data_structures:: fx:: FxIndexMap ;
55use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
66use rustc_middle:: mir:: * ;
77use rustc_middle:: thir:: { self , * } ;
@@ -272,7 +272,11 @@ pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
272272 /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from
273273 /// bindings inside deref patterns.
274274 scrutinee_base : PlaceBase ,
275- fake_borrows : FxIndexSet < Place < ' tcx > > ,
275+ /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest
276+ /// borrow (i.e. Deep > Shallow).
277+ /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are
278+ /// dereferences are also borrowed with the same of stronger borrow kind.
279+ fake_borrows : FxIndexMap < Place < ' tcx > , FakeBorrowKind > ,
276280}
277281
278282/// Determine the set of places that have to be stable across match guards.
@@ -315,9 +319,9 @@ pub(super) fn collect_fake_borrows<'tcx>(
315319 candidates : & [ & mut Candidate < ' _ , ' tcx > ] ,
316320 temp_span : Span ,
317321 scrutinee_base : PlaceBase ,
318- ) -> Vec < ( Place < ' tcx > , Local ) > {
322+ ) -> Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > {
319323 let mut collector =
320- FakeBorrowCollector { cx, scrutinee_base, fake_borrows : FxIndexSet :: default ( ) } ;
324+ FakeBorrowCollector { cx, scrutinee_base, fake_borrows : FxIndexMap :: default ( ) } ;
321325 for candidate in candidates. iter ( ) {
322326 collector. visit_candidate ( candidate) ;
323327 }
@@ -326,40 +330,40 @@ pub(super) fn collect_fake_borrows<'tcx>(
326330 let tcx = cx. tcx ;
327331 fake_borrows
328332 . iter ( )
329- . copied ( )
330- . map ( |matched_place| {
333+ . map ( |( matched_place, borrow_kind) | {
331334 let fake_borrow_deref_ty = matched_place. ty ( & cx. local_decls , tcx) . ty ;
332335 let fake_borrow_ty =
333336 Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , fake_borrow_deref_ty) ;
334337 let mut fake_borrow_temp = LocalDecl :: new ( fake_borrow_ty, temp_span) ;
335338 fake_borrow_temp. local_info = ClearCrossCrate :: Set ( Box :: new ( LocalInfo :: FakeBorrow ) ) ;
336339 let fake_borrow_temp = cx. local_decls . push ( fake_borrow_temp) ;
337- ( matched_place, fake_borrow_temp)
340+ ( * matched_place, fake_borrow_temp, * borrow_kind )
338341 } )
339342 . collect ( )
340343}
341344
342345impl < ' a , ' b , ' tcx > FakeBorrowCollector < ' a , ' b , ' tcx > {
343346 // Fake borrow this place and its dereference prefixes.
344- fn fake_borrow ( & mut self , place : Place < ' tcx > ) {
345- let new = self . fake_borrows . insert ( place) ;
346- if !new {
347+ fn fake_borrow ( & mut self , place : Place < ' tcx > , kind : FakeBorrowKind ) {
348+ if self . fake_borrows . get ( & place) . is_some_and ( |k| * k >= kind) {
347349 return ;
348350 }
351+ self . fake_borrows . insert ( place, kind) ;
349352 // Also fake borrow the prefixes of any fake borrow.
350- self . fake_borrow_deref_prefixes ( place) ;
353+ self . fake_borrow_deref_prefixes ( place, kind ) ;
351354 }
352355
353356 // Fake borrow the prefixes of this place that are dereferences.
354- fn fake_borrow_deref_prefixes ( & mut self , place : Place < ' tcx > ) {
357+ fn fake_borrow_deref_prefixes ( & mut self , place : Place < ' tcx > , kind : FakeBorrowKind ) {
355358 for ( place_ref, elem) in place. as_ref ( ) . iter_projections ( ) . rev ( ) {
356359 if let ProjectionElem :: Deref = elem {
357360 // Insert a shallow borrow after a deref. For other projections the borrow of
358361 // `place_ref` will conflict with any mutation of `place.base`.
359- let new = self . fake_borrows . insert ( place_ref. to_place ( self . cx . tcx ) ) ;
360- if !new {
362+ let place = place_ref. to_place ( self . cx . tcx ) ;
363+ if self . fake_borrows . get ( & place ) . is_some_and ( |k| * k >= kind ) {
361364 return ;
362365 }
366+ self . fake_borrows . insert ( place, kind) ;
363367 }
364368 }
365369 }
@@ -400,15 +404,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
400404 // // UB because we reached the unreachable.
401405 // }
402406 // ```
403- // FIXME(deref_patterns): Hence we fake borrow using a non-shallow borrow.
407+ // Hence we fake borrow using a deep borrow.
404408 if let Some ( place) = match_pair. place {
405- // FIXME(deref_patterns): use a non-shallow borrow.
406- self . fake_borrow ( place) ;
409+ self . fake_borrow ( place, FakeBorrowKind :: Deep ) ;
407410 }
408411 } else {
409412 // Insert a Shallow borrow of any place that is switched on.
410413 if let Some ( place) = match_pair. place {
411- self . fake_borrow ( place) ;
414+ self . fake_borrow ( place, FakeBorrowKind :: Shallow ) ;
412415 }
413416
414417 for subpair in & match_pair. subpairs {
@@ -448,7 +451,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
448451 // _ if { u = true; false } => (),
449452 // x => (),
450453 // }
451- self . fake_borrow_deref_prefixes ( * source) ;
454+ self . fake_borrow_deref_prefixes ( * source, FakeBorrowKind :: Shallow ) ;
452455 }
453456}
454457
0 commit comments