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, TypeVariableOriginKind};
6
6
use rustc_middle::mir::*;
7
7
use rustc_middle::thir::{self, *};
@@ -272,7 +272,11 @@ pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
272
272
/// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from
273
273
/// bindings inside deref patterns.
274
274
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>,
276
280
}
277
281
278
282
/// Determine the set of places that have to be stable across match guards.
@@ -315,9 +319,9 @@ pub(super) fn collect_fake_borrows<'tcx>(
315
319
candidates: &[&mut Candidate<'_, 'tcx>],
316
320
temp_span: Span,
317
321
scrutinee_base: PlaceBase,
318
- ) -> Vec<(Place<'tcx>, Local)> {
322
+ ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind )> {
319
323
let mut collector =
320
- FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexSet ::default() };
324
+ FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap ::default() };
321
325
for candidate in candidates.iter() {
322
326
collector.visit_candidate(candidate);
323
327
}
@@ -326,40 +330,40 @@ pub(super) fn collect_fake_borrows<'tcx>(
326
330
let tcx = cx.tcx;
327
331
fake_borrows
328
332
.iter()
329
- .copied()
330
- .map(|matched_place| {
333
+ .map(|(matched_place, borrow_kind)| {
331
334
let fake_borrow_deref_ty = matched_place.ty(&cx.local_decls, tcx).ty;
332
335
let fake_borrow_ty =
333
336
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty);
334
337
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
335
338
fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
336
339
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 )
338
341
})
339
342
.collect()
340
343
}
341
344
342
345
impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
343
346
// 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) {
347
349
return;
348
350
}
351
+ self.fake_borrows.insert(place, kind);
349
352
// Also fake borrow the prefixes of any fake borrow.
350
- self.fake_borrow_deref_prefixes(place);
353
+ self.fake_borrow_deref_prefixes(place, kind );
351
354
}
352
355
353
356
// 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 ) {
355
358
for (place_ref, elem) in place.as_ref().iter_projections().rev() {
356
359
if let ProjectionElem::Deref = elem {
357
360
// Insert a shallow borrow after a deref. For other projections the borrow of
358
361
// `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) {
361
364
return;
362
365
}
366
+ self.fake_borrows.insert(place, kind);
363
367
}
364
368
}
365
369
}
@@ -400,15 +404,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
400
404
// // UB because we reached the unreachable.
401
405
// }
402
406
// ```
403
- // FIXME(deref_patterns): Hence we fake borrow using a non-shallow borrow.
407
+ // Hence we fake borrow using a deep borrow.
404
408
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);
407
410
}
408
411
} else {
409
412
// Insert a Shallow borrow of any place that is switched on.
410
413
if let Some(place) = match_pair.place {
411
- self.fake_borrow(place);
414
+ self.fake_borrow(place, FakeBorrowKind::Shallow );
412
415
}
413
416
414
417
for subpair in &match_pair.subpairs {
@@ -448,7 +451,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
448
451
// _ if { u = true; false } => (),
449
452
// x => (),
450
453
// }
451
- self.fake_borrow_deref_prefixes(*source);
454
+ self.fake_borrow_deref_prefixes(*source, FakeBorrowKind::Shallow );
452
455
}
453
456
}
454
457
0 commit comments