Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit b6c4097

Browse files
Support let &mut x = &&mut 0;
1 parent 4cd87c4 commit b6c4097

File tree

4 files changed

+60
-10
lines changed

4 files changed

+60
-10
lines changed

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
299299
if mutbls_match {
300300
(expected, INITIAL_BM, true)
301301
} else {
302-
let mut new_bm = def_bm;
303-
if new_bm.0 == ByRef::Yes(Mutability::Mut) && mutbl == Mutability::Not {
304-
new_bm.0 = ByRef::Yes(Mutability::Not);
305-
}
306-
(expected, new_bm, false)
302+
let (new_ty, new_bm) = if mutbl == Mutability::Mut {
303+
self.peel_off_references(pat, expected, def_bm, Mutability::Not)
304+
} else {
305+
let new_byref = if def_bm.0 == ByRef::Yes(Mutability::Mut) {
306+
ByRef::Yes(Mutability::Not)
307+
} else {
308+
def_bm.0
309+
};
310+
(expected, BindingAnnotation(new_byref, def_bm.1))
311+
};
312+
(new_ty, new_bm, false)
307313
}
308314
} else {
309315
(expected, INITIAL_BM, mutbls_match)
310316
}
311317
}
312318
AdjustMode::Peel => {
313-
let peeled = self.peel_off_references(pat, expected, def_bm);
319+
let peeled = self.peel_off_references(pat, expected, def_bm, Mutability::Mut);
314320
(peeled.0, peeled.1, false)
315321
}
316322
}
@@ -392,6 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
392398
pat: &'tcx Pat<'tcx>,
393399
expected: Ty<'tcx>,
394400
mut def_bm: BindingAnnotation,
401+
max_mutability: Mutability,
395402
) -> (Ty<'tcx>, BindingAnnotation) {
396403
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
397404
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
@@ -403,7 +410,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
403410
//
404411
// See the examples in `ui/match-defbm*.rs`.
405412
let mut pat_adjustments = vec![];
406-
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
413+
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
414+
&& inner_mutability <= max_mutability
415+
{
407416
debug!("inspecting {:?}", expected);
408417

409418
debug!("current discriminant is Ref, inserting implicit deref");

tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,13 @@ pub fn main() {
3838
if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
3939
let _: &u32 = x;
4040
}
41+
42+
let &mut x = &&mut 0;
43+
let _: &u32 = x;
44+
45+
let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
46+
let _: &u32 = x;
47+
48+
let &mut &mut &mut &mut x = &mut &&&&mut &&&mut &mut 0;
49+
let _: &u32 = x;
4150
}

tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,12 @@ pub fn main() {
1717
if let Some(&Some(&x)) = Some(&Some(&mut 0)) {
1818
//~^ ERROR: mismatched types
1919
}
20+
21+
let &mut x = &&0;
22+
//~^ ERROR: mismatched types
23+
let _: &u32 = x;
24+
25+
let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
26+
//~^ ERROR: mismatched types
27+
let _: &u32 = x;
2028
}

tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ error[E0308]: mismatched types
44
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
55
| ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>`
66
| |
7-
| types differ in mutability
7+
| expected `Option<{integer}>`, found `&mut _`
88
|
9-
= note: expected reference `&Option<{integer}>`
9+
= note: expected enum `Option<{integer}>`
1010
found mutable reference `&mut _`
1111

1212
error[E0308]: mismatched types
@@ -46,6 +46,30 @@ help: consider removing `&` from the pattern
4646
LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) {
4747
| ~
4848

49-
error: aborting due to 4 previous errors
49+
error[E0308]: mismatched types
50+
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:9
51+
|
52+
LL | let &mut x = &&0;
53+
| ^^^^^^ --- this expression has type `&&{integer}`
54+
| |
55+
| expected integer, found `&mut _`
56+
| help: to declare a mutable variable use: `mut x`
57+
|
58+
= note: expected type `{integer}`
59+
found mutable reference `&mut _`
60+
61+
error[E0308]: mismatched types
62+
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:9
63+
|
64+
LL | let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
65+
| ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
66+
| |
67+
| expected integer, found `&mut _`
68+
| help: to declare a mutable variable use: `mut x`
69+
|
70+
= note: expected type `{integer}`
71+
found mutable reference `&mut _`
72+
73+
error: aborting due to 6 previous errors
5074

5175
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)