Allow mutable bindings inside deref patterns

This commit is contained in:
Nadrieril 2024-04-04 00:46:35 +02:00
parent 5c4909b8e1
commit 377e095371
4 changed files with 48 additions and 15 deletions

View File

@ -1163,7 +1163,7 @@ enum TestCase<'pat, 'tcx> {
Constant { value: mir::Const<'tcx> }, Constant { value: mir::Const<'tcx> },
Range(&'pat PatRange<'tcx>), Range(&'pat PatRange<'tcx>),
Slice { len: usize, variable_length: bool }, Slice { len: usize, variable_length: bool },
Deref { temp: Place<'tcx> }, Deref { temp: Place<'tcx>, mutability: Mutability },
Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
} }
@ -1224,10 +1224,11 @@ enum TestKind<'tcx> {
/// Test that the length of the slice is equal to `len`. /// Test that the length of the slice is equal to `len`.
Len { len: u64, op: BinOp }, Len { len: u64, op: BinOp },
/// Call `Deref::deref` on the value. /// Call `Deref::deref[_mut]` on the value.
Deref { Deref {
/// Temporary to store the result of `deref()`. /// Temporary to store the result of `deref()`/`deref_mut()`.
temp: Place<'tcx>, temp: Place<'tcx>,
mutability: Mutability,
}, },
} }

View File

@ -42,7 +42,7 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
TestKind::Len { len: len as u64, op } TestKind::Len { len: len as u64, op }
} }
TestCase::Deref { temp } => TestKind::Deref { temp }, TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
@ -149,7 +149,15 @@ pub(super) fn perform_test(
let ref_str = self.temp(ref_str_ty, test.span); let ref_str = self.temp(ref_str_ty, test.span);
let eq_block = self.cfg.start_new_block(); let eq_block = self.cfg.start_new_block();
// `let ref_str: &str = <String as Deref>::deref(&place);` // `let ref_str: &str = <String as Deref>::deref(&place);`
self.call_deref(block, eq_block, place, ty, ref_str, test.span); self.call_deref(
block,
eq_block,
place,
Mutability::Not,
ty,
ref_str,
test.span,
);
self.non_scalar_compare( self.non_scalar_compare(
eq_block, eq_block,
success_block, success_block,
@ -249,37 +257,46 @@ pub(super) fn perform_test(
); );
} }
TestKind::Deref { temp } => { TestKind::Deref { temp, mutability } => {
let ty = place_ty.ty; let ty = place_ty.ty;
let target = target_block(TestBranch::Success); let target = target_block(TestBranch::Success);
self.call_deref(block, target, place, ty, temp, test.span); self.call_deref(block, target, place, mutability, ty, temp, test.span);
} }
} }
} }
/// Perform `let temp = <ty as Deref>::deref(&place)`. /// Perform `let temp = <ty as Deref>::deref(&place)`.
/// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
pub(super) fn call_deref( pub(super) fn call_deref(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
target_block: BasicBlock, target_block: BasicBlock,
place: Place<'tcx>, place: Place<'tcx>,
mutability: Mutability,
ty: Ty<'tcx>, ty: Ty<'tcx>,
temp: Place<'tcx>, temp: Place<'tcx>,
span: Span, span: Span,
) { ) {
let (trait_item, method) = match mutability {
Mutability::Not => (LangItem::Deref, sym::deref),
Mutability::Mut => (LangItem::DerefMut, sym::deref_mut),
};
let borrow_kind = super::util::ref_pat_borrow_kind(mutability);
let source_info = self.source_info(span); let source_info = self.source_info(span);
let re_erased = self.tcx.lifetimes.re_erased; let re_erased = self.tcx.lifetimes.re_erased;
let deref = self.tcx.require_lang_item(LangItem::Deref, None); let trait_item = self.tcx.require_lang_item(trait_item, None);
let method = trait_method(self.tcx, deref, sym::deref, [ty]); let method = trait_method(self.tcx, trait_item, method, [ty]);
let ref_src = self.temp(Ty::new_imm_ref(self.tcx, re_erased, ty), span); let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
// `let ref_src = &src_place;` // `let ref_src = &src_place;`
// or `let ref_src = &mut src_place;`
self.cfg.push_assign( self.cfg.push_assign(
block, block,
source_info, source_info,
ref_src, ref_src,
Rvalue::Ref(re_erased, BorrowKind::Shared, place), Rvalue::Ref(re_erased, borrow_kind, place),
); );
// `let temp = <Ty as Deref>::deref(ref_src);` // `let temp = <Ty as Deref>::deref(ref_src);`
// or `let temp = <Ty as DerefMut>::deref_mut(ref_src);`
self.cfg.terminate( self.cfg.terminate(
block, block,
source_info, source_info,
@ -686,7 +703,7 @@ pub(super) fn sort_candidate(
} }
} }
(TestKind::Deref { temp: test_temp }, TestCase::Deref { temp }) (TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
if test_temp == temp => if test_temp == temp =>
{ {
fully_matched = true; fully_matched = true;

View File

@ -249,15 +249,15 @@ pub(in crate::build) fn new(
default_irrefutable() default_irrefutable()
} }
PatKind::DerefPattern { ref subpattern, .. } => { PatKind::DerefPattern { ref subpattern, mutability } => {
// Create a new temporary for each deref pattern. // Create a new temporary for each deref pattern.
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
let temp = cx.temp( let temp = cx.temp(
Ty::new_imm_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty), Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
pattern.span, pattern.span,
); );
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
TestCase::Deref { temp } TestCase::Deref { temp, mutability }
} }
}; };

View File

@ -24,6 +24,19 @@ fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
} }
} }
fn ref_mut(val: u32) -> u32 {
let mut b = Box::new(0u32);
match &mut b {
deref!(_x) if false => unreachable!(),
deref!(x) => {
*x = val;
}
_ => unreachable!(),
}
let deref!(x) = &b else { unreachable!() };
*x
}
fn main() { fn main() {
assert_eq!(simple_vec(vec![1]), 1); assert_eq!(simple_vec(vec![1]), 1);
assert_eq!(simple_vec(vec![1, 2]), 202); assert_eq!(simple_vec(vec![1, 2]), 202);
@ -34,4 +47,6 @@ fn main() {
assert_eq!(nested_vec(vec![vec![1, 42]]), 42); assert_eq!(nested_vec(vec![vec![1, 42]]), 42);
assert_eq!(nested_vec(vec![vec![1, 2, 3]]), 6); assert_eq!(nested_vec(vec![vec![1, 2, 3]]), 6);
assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1); assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1);
assert_eq!(ref_mut(42), 42)
} }