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> },
|
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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user