Allow mutable bindings inside deref patterns
This commit is contained in:
parent
5c4909b8e1
commit
377e095371
@ -1163,7 +1163,7 @@ enum TestCase<'pat, 'tcx> {
|
||||
Constant { value: mir::Const<'tcx> },
|
||||
Range(&'pat PatRange<'tcx>),
|
||||
Slice { len: usize, variable_length: bool },
|
||||
Deref { temp: Place<'tcx> },
|
||||
Deref { temp: Place<'tcx>, mutability: Mutability },
|
||||
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
|
||||
}
|
||||
|
||||
@ -1224,10 +1224,11 @@ enum TestKind<'tcx> {
|
||||
/// Test that the length of the slice is equal to `len`.
|
||||
Len { len: u64, op: BinOp },
|
||||
|
||||
/// Call `Deref::deref` on the value.
|
||||
/// Call `Deref::deref[_mut]` on the value.
|
||||
Deref {
|
||||
/// Temporary to store the result of `deref()`.
|
||||
/// Temporary to store the result of `deref()`/`deref_mut()`.
|
||||
temp: Place<'tcx>,
|
||||
mutability: Mutability,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
|
||||
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"),
|
||||
|
||||
@ -149,7 +149,15 @@ pub(super) fn perform_test(
|
||||
let ref_str = self.temp(ref_str_ty, test.span);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
// `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(
|
||||
eq_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 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)`.
|
||||
/// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
|
||||
pub(super) fn call_deref(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
target_block: BasicBlock,
|
||||
place: Place<'tcx>,
|
||||
mutability: Mutability,
|
||||
ty: Ty<'tcx>,
|
||||
temp: Place<'tcx>,
|
||||
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 re_erased = self.tcx.lifetimes.re_erased;
|
||||
let deref = self.tcx.require_lang_item(LangItem::Deref, None);
|
||||
let method = trait_method(self.tcx, deref, sym::deref, [ty]);
|
||||
let ref_src = self.temp(Ty::new_imm_ref(self.tcx, re_erased, ty), span);
|
||||
let trait_item = self.tcx.require_lang_item(trait_item, None);
|
||||
let method = trait_method(self.tcx, trait_item, method, [ty]);
|
||||
let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
|
||||
// `let ref_src = &src_place;`
|
||||
// or `let ref_src = &mut src_place;`
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
ref_src,
|
||||
Rvalue::Ref(re_erased, BorrowKind::Shared, place),
|
||||
Rvalue::Ref(re_erased, borrow_kind, place),
|
||||
);
|
||||
// `let temp = <Ty as Deref>::deref(ref_src);`
|
||||
// or `let temp = <Ty as DerefMut>::deref_mut(ref_src);`
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
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 =>
|
||||
{
|
||||
fully_matched = true;
|
||||
|
@ -249,15 +249,15 @@ pub(in crate::build) fn new(
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, .. } => {
|
||||
PatKind::DerefPattern { ref subpattern, mutability } => {
|
||||
// Create a new temporary for each deref pattern.
|
||||
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
|
||||
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,
|
||||
);
|
||||
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
|
||||
TestCase::Deref { temp }
|
||||
TestCase::Deref { temp, mutability }
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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() {
|
||||
assert_eq!(simple_vec(vec![1]), 1);
|
||||
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, 2, 3]]), 6);
|
||||
assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1);
|
||||
|
||||
assert_eq!(ref_mut(42), 42)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user