Skip to content

Commit 2e22b35

Browse files
committed
Allow mutable bindings inside deref patterns
1 parent 1d737e7 commit 2e22b35

File tree

4 files changed

+48
-15
lines changed

4 files changed

+48
-15
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ enum TestCase<'pat, 'tcx> {
11681168
Constant { value: mir::Const<'tcx> },
11691169
Range(&'pat PatRange<'tcx>),
11701170
Slice { len: usize, variable_length: bool },
1171-
Deref { temp: Place<'tcx> },
1171+
Deref { temp: Place<'tcx>, mutability: Mutability },
11721172
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
11731173
}
11741174

@@ -1229,10 +1229,11 @@ enum TestKind<'tcx> {
12291229
/// Test that the length of the slice is equal to `len`.
12301230
Len { len: u64, op: BinOp },
12311231

1232-
/// Call `Deref::deref` on the value.
1232+
/// Call `Deref::deref[_mut]` on the value.
12331233
Deref {
1234-
/// Temporary to store the result of `deref()`.
1234+
/// Temporary to store the result of `deref()`/`deref_mut()`.
12351235
temp: Place<'tcx>,
1236+
mutability: Mutability,
12361237
},
12371238
}
12381239

compiler/rustc_mir_build/src/build/matches/test.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4242
TestKind::Len { len: len as u64, op }
4343
}
4444

45-
TestCase::Deref { temp } => TestKind::Deref { temp },
45+
TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
4646

4747
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
4848

@@ -149,7 +149,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
149149
let ref_str = self.temp(ref_str_ty, test.span);
150150
let eq_block = self.cfg.start_new_block();
151151
// `let ref_str: &str = <String as Deref>::deref(&place);`
152-
self.call_deref(block, eq_block, place, ty, ref_str, test.span);
152+
self.call_deref(
153+
block,
154+
eq_block,
155+
place,
156+
Mutability::Not,
157+
ty,
158+
ref_str,
159+
test.span,
160+
);
153161
self.non_scalar_compare(
154162
eq_block,
155163
success_block,
@@ -249,37 +257,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
249257
);
250258
}
251259

252-
TestKind::Deref { temp } => {
260+
TestKind::Deref { temp, mutability } => {
253261
let ty = place_ty.ty;
254262
let target = target_block(TestBranch::Success);
255-
self.call_deref(block, target, place, ty, temp, test.span);
263+
self.call_deref(block, target, place, mutability, ty, temp, test.span);
256264
}
257265
}
258266
}
259267

260268
/// Perform `let temp = <ty as Deref>::deref(&place)`.
269+
/// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
261270
pub(super) fn call_deref(
262271
&mut self,
263272
block: BasicBlock,
264273
target_block: BasicBlock,
265274
place: Place<'tcx>,
275+
mutability: Mutability,
266276
ty: Ty<'tcx>,
267277
temp: Place<'tcx>,
268278
span: Span,
269279
) {
280+
let (trait_item, method) = match mutability {
281+
Mutability::Not => (LangItem::Deref, sym::deref),
282+
Mutability::Mut => (LangItem::DerefMut, sym::deref_mut),
283+
};
284+
let borrow_kind = super::util::ref_pat_borrow_kind(mutability);
270285
let source_info = self.source_info(span);
271286
let re_erased = self.tcx.lifetimes.re_erased;
272-
let deref = self.tcx.require_lang_item(LangItem::Deref, None);
273-
let method = trait_method(self.tcx, deref, sym::deref, [ty]);
274-
let ref_src = self.temp(Ty::new_imm_ref(self.tcx, re_erased, ty), span);
287+
let trait_item = self.tcx.require_lang_item(trait_item, None);
288+
let method = trait_method(self.tcx, trait_item, method, [ty]);
289+
let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
275290
// `let ref_src = &src_place;`
291+
// or `let ref_src = &mut src_place;`
276292
self.cfg.push_assign(
277293
block,
278294
source_info,
279295
ref_src,
280-
Rvalue::Ref(re_erased, BorrowKind::Shared, place),
296+
Rvalue::Ref(re_erased, borrow_kind, place),
281297
);
282298
// `let temp = <Ty as Deref>::deref(ref_src);`
299+
// or `let temp = <Ty as DerefMut>::deref_mut(ref_src);`
283300
self.cfg.terminate(
284301
block,
285302
source_info,
@@ -686,7 +703,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
686703
}
687704
}
688705

689-
(TestKind::Deref { temp: test_temp }, TestCase::Deref { temp })
706+
(TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
690707
if test_temp == temp =>
691708
{
692709
fully_matched = true;

compiler/rustc_mir_build/src/build/matches/util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -250,15 +250,15 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
250250
default_irrefutable()
251251
}
252252

253-
PatKind::DerefPattern { ref subpattern, .. } => {
253+
PatKind::DerefPattern { ref subpattern, mutability } => {
254254
// Create a new temporary for each deref pattern.
255255
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
256256
let temp = cx.temp(
257-
Ty::new_imm_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty),
257+
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
258258
pattern.span,
259259
);
260260
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
261-
TestCase::Deref { temp }
261+
TestCase::Deref { temp, mutability }
262262
}
263263
};
264264

tests/ui/pattern/deref-patterns/bindings.rs

+15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
2424
}
2525
}
2626

27+
fn ref_mut(val: u32) -> u32 {
28+
let mut b = Box::new(0u32);
29+
match &mut b {
30+
deref!(_x) if false => unreachable!(),
31+
deref!(x) => {
32+
*x = val;
33+
}
34+
_ => unreachable!(),
35+
}
36+
let deref!(x) = &b else { unreachable!() };
37+
*x
38+
}
39+
2740
fn main() {
2841
assert_eq!(simple_vec(vec![1]), 1);
2942
assert_eq!(simple_vec(vec![1, 2]), 202);
@@ -34,4 +47,6 @@ fn main() {
3447
assert_eq!(nested_vec(vec![vec![1, 42]]), 42);
3548
assert_eq!(nested_vec(vec![vec![1, 2, 3]]), 6);
3649
assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1);
50+
51+
assert_eq!(ref_mut(42), 42)
3752
}

0 commit comments

Comments
 (0)