Skip to content

Commit ddf74a4

Browse files
committed
"structural" ruleset: match against the inherited ref when a reference pattern doesn't match the mutability of an inner reference
This is the `Deref(EatInner, FallbackToOuter)` rule in Typing Rust Patterns.
1 parent 1931a64 commit ddf74a4

File tree

5 files changed

+71
-64
lines changed

5 files changed

+71
-64
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -2297,15 +2297,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22972297
return expected;
22982298
}
22992299
InheritedRefMatchRule::EatInner => {
2300-
if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
2300+
if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2301+
&& pat_mutbl <= r_mutbl
2302+
{
23012303
// Match against the reference type; don't consume the inherited ref.
2304+
// NB: The check for compatible pattern and ref type mutability assumes that
2305+
// `&` patterns can match against mutable references (RFC 3627, Rule 5). If
2306+
// we implement a pattern typing ruleset with Rule 4 (including the fallback
2307+
// to matching the inherited ref when the inner ref can't match) but not
2308+
// Rule 5, we'll need to check that here.
23022309
// NB: For RFC 3627's Rule 3, we limit the default binding mode's ref
23032310
// mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing
23042311
// ruleset with Rule 4 but not Rule 3, we'll need to check that here.
23052312
let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
23062313
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
23072314
} else {
2308-
// The expected type isn't a reference, so match against the inherited ref.
2315+
// The reference pattern can't match against the expected type, so try
2316+
// matching against the inherited ref instead.
23092317
if pat_mutbl > inh_mut {
23102318
// We can't match an inherited shared reference with `&mut`.
23112319
// NB: This assumes that `&` patterns can match against mutable

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/pattern-errors.rs:15:17
2+
--> $DIR/pattern-errors.rs:10:17
33
|
44
LL | if let Some(&mut x) = &Some(&mut 0) {
55
| ^^^^^
@@ -11,7 +11,7 @@ LL | if let Some(&x) = &Some(&mut 0) {
1111
| ~
1212

1313
error[E0308]: mismatched types
14-
--> $DIR/pattern-errors.rs:19:17
14+
--> $DIR/pattern-errors.rs:14:17
1515
|
1616
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
1717
| ^^^^^
@@ -23,7 +23,7 @@ LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) {
2323
| ~
2424

2525
error[E0308]: mismatched types
26-
--> $DIR/pattern-errors.rs:23:22
26+
--> $DIR/pattern-errors.rs:18:22
2727
|
2828
LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
2929
| ^^^^^
@@ -35,7 +35,7 @@ LL | if let Some(Some(&x)) = &Some(Some(&mut 0)) {
3535
| ~
3636

3737
error[E0308]: mismatched types
38-
--> $DIR/pattern-errors.rs:28:17
38+
--> $DIR/pattern-errors.rs:23:17
3939
|
4040
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
4141
| ^^^^^
@@ -47,7 +47,7 @@ LL | if let Some(&Some(&_)) = &Some(&Some(0)) {
4747
| ~
4848

4949
error[E0308]: mismatched types
50-
--> $DIR/pattern-errors.rs:34:23
50+
--> $DIR/pattern-errors.rs:29:23
5151
|
5252
LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
5353
| ^^^^^
@@ -59,7 +59,7 @@ LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) {
5959
| ~
6060

6161
error[E0308]: mismatched types
62-
--> $DIR/pattern-errors.rs:40:17
62+
--> $DIR/pattern-errors.rs:35:17
6363
|
6464
LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
6565
| ^^^^^
@@ -71,7 +71,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) {
7171
| ~
7272

7373
error[E0308]: mismatched types
74-
--> $DIR/pattern-errors.rs:43:17
74+
--> $DIR/pattern-errors.rs:38:17
7575
|
7676
LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
7777
| ^^^^^
@@ -83,7 +83,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) {
8383
| ~
8484

8585
error[E0308]: mismatched types
86-
--> $DIR/pattern-errors.rs:123:10
86+
--> $DIR/pattern-errors.rs:118:10
8787
|
8888
LL | let [&mut x] = &[&mut 0];
8989
| ^^^^^
@@ -95,7 +95,7 @@ LL | let [&x] = &[&mut 0];
9595
| ~
9696

9797
error[E0308]: mismatched types
98-
--> $DIR/pattern-errors.rs:128:10
98+
--> $DIR/pattern-errors.rs:123:10
9999
|
100100
LL | let [&mut &x] = &[&mut 0];
101101
| ^^^^^
@@ -107,7 +107,7 @@ LL | let [&&x] = &[&mut 0];
107107
| ~
108108

109109
error[E0308]: mismatched types
110-
--> $DIR/pattern-errors.rs:133:10
110+
--> $DIR/pattern-errors.rs:128:10
111111
|
112112
LL | let [&mut &ref x] = &[&mut 0];
113113
| ^^^^^
@@ -119,7 +119,7 @@ LL | let [&&ref x] = &[&mut 0];
119119
| ~
120120

121121
error[E0308]: mismatched types
122-
--> $DIR/pattern-errors.rs:138:10
122+
--> $DIR/pattern-errors.rs:133:10
123123
|
124124
LL | let [&mut &(mut x)] = &[&mut 0];
125125
| ^^^^^

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs

-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@
77
#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
88

99
pub fn main() {
10-
if let Some(&mut x) = &mut Some(&0) {
11-
//[structural]~^ ERROR: mismatched types
12-
let _: &u32 = x;
13-
}
14-
1510
if let Some(&mut x) = &Some(&mut 0) {
1611
//[classic]~^ ERROR: mismatched types
1712
let _: &u32 = x;

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr

+26-45
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
error[E0308]: mismatched types
2-
--> $DIR/pattern-errors.rs:10:17
2+
--> $DIR/pattern-errors.rs:23:17
33
|
4-
LL | if let Some(&mut x) = &mut Some(&0) {
5-
| ^^^^^^ ------------- this expression has type `&mut Option<&{integer}>`
6-
| |
7-
| types differ in mutability
8-
|
9-
= note: expected reference `&{integer}`
10-
found mutable reference `&mut _`
11-
note: to declare a mutable binding use: `mut x`
12-
--> $DIR/pattern-errors.rs:10:17
4+
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
5+
| ^^^^^
136
|
14-
LL | if let Some(&mut x) = &mut Some(&0) {
15-
| ^^^^^^
16-
help: consider removing `&mut` from the pattern
7+
= note: cannot match inherited `&` with `&mut` pattern
8+
help: replace this `&mut` pattern with `&`
179
|
18-
LL | if let Some(x) = &mut Some(&0) {
10+
LL | if let Some(&Some(&_)) = &Some(&Some(0)) {
1911
| ~
2012

2113
error[E0308]: mismatched types
22-
--> $DIR/pattern-errors.rs:28:17
23-
|
24-
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
25-
| ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>`
26-
| |
27-
| types differ in mutability
28-
|
29-
= note: expected reference `&Option<{integer}>`
30-
found mutable reference `&mut _`
31-
32-
error[E0308]: mismatched types
33-
--> $DIR/pattern-errors.rs:31:23
14+
--> $DIR/pattern-errors.rs:26:23
3415
|
3516
LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
3617
| ^^^^^
@@ -42,7 +23,7 @@ LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) {
4223
| ~
4324

4425
error[E0308]: mismatched types
45-
--> $DIR/pattern-errors.rs:34:23
26+
--> $DIR/pattern-errors.rs:29:23
4627
|
4728
LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
4829
| ^^^^^
@@ -54,7 +35,7 @@ LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) {
5435
| ~
5536

5637
error[E0308]: mismatched types
57-
--> $DIR/pattern-errors.rs:37:29
38+
--> $DIR/pattern-errors.rs:32:29
5839
|
5940
LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
6041
| ^^^^^
@@ -66,7 +47,7 @@ LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) {
6647
| ~
6748

6849
error[E0308]: mismatched types
69-
--> $DIR/pattern-errors.rs:40:17
50+
--> $DIR/pattern-errors.rs:35:17
7051
|
7152
LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
7253
| ^^^^^
@@ -78,7 +59,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) {
7859
| ~
7960

8061
error[E0308]: mismatched types
81-
--> $DIR/pattern-errors.rs:43:17
62+
--> $DIR/pattern-errors.rs:38:17
8263
|
8364
LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
8465
| ^^^^^
@@ -90,7 +71,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) {
9071
| ~
9172

9273
error[E0308]: mismatched types
93-
--> $DIR/pattern-errors.rs:49:11
74+
--> $DIR/pattern-errors.rs:44:11
9475
|
9576
LL | let &[&mut x] = &&mut [0];
9677
| ^^^^^
@@ -102,7 +83,7 @@ LL | let &[&x] = &&mut [0];
10283
| ~
10384

10485
error[E0308]: mismatched types
105-
--> $DIR/pattern-errors.rs:54:11
86+
--> $DIR/pattern-errors.rs:49:11
10687
|
10788
LL | let &[&mut x] = &mut &mut [0];
10889
| ^^^^^
@@ -114,7 +95,7 @@ LL | let &[&x] = &mut &mut [0];
11495
| ~
11596

11697
error[E0308]: mismatched types
117-
--> $DIR/pattern-errors.rs:59:11
98+
--> $DIR/pattern-errors.rs:54:11
11899
|
119100
LL | let &[&mut ref x] = &&mut [0];
120101
| ^^^^^
@@ -126,7 +107,7 @@ LL | let &[&ref x] = &&mut [0];
126107
| ~
127108

128109
error[E0308]: mismatched types
129-
--> $DIR/pattern-errors.rs:64:11
110+
--> $DIR/pattern-errors.rs:59:11
130111
|
131112
LL | let &[&mut ref x] = &mut &mut [0];
132113
| ^^^^^
@@ -138,7 +119,7 @@ LL | let &[&ref x] = &mut &mut [0];
138119
| ~
139120

140121
error[E0308]: mismatched types
141-
--> $DIR/pattern-errors.rs:69:11
122+
--> $DIR/pattern-errors.rs:64:11
142123
|
143124
LL | let &[&mut mut x] = &&mut [0];
144125
| ^^^^^
@@ -150,7 +131,7 @@ LL | let &[&mut x] = &&mut [0];
150131
| ~
151132

152133
error[E0308]: mismatched types
153-
--> $DIR/pattern-errors.rs:74:11
134+
--> $DIR/pattern-errors.rs:69:11
154135
|
155136
LL | let &[&mut mut x] = &mut &mut [0];
156137
| ^^^^^
@@ -162,7 +143,7 @@ LL | let &[&mut x] = &mut &mut [0];
162143
| ~
163144

164145
error[E0658]: binding cannot be both mutable and by-reference
165-
--> $DIR/pattern-errors.rs:81:12
146+
--> $DIR/pattern-errors.rs:76:12
166147
|
167148
LL | let [&(mut x)] = &[&0];
168149
| ^^^^
@@ -172,7 +153,7 @@ LL | let [&(mut x)] = &[&0];
172153
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
173154

174155
error[E0658]: binding cannot be both mutable and by-reference
175-
--> $DIR/pattern-errors.rs:85:12
156+
--> $DIR/pattern-errors.rs:80:12
176157
|
177158
LL | let [&(mut x)] = &mut [&0];
178159
| ^^^^
@@ -182,7 +163,7 @@ LL | let [&(mut x)] = &mut [&0];
182163
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
183164

184165
error[E0308]: mismatched types
185-
--> $DIR/pattern-errors.rs:91:11
166+
--> $DIR/pattern-errors.rs:86:11
186167
|
187168
LL | let [&&mut x] = &[&mut 0];
188169
| ^^^^^
@@ -194,7 +175,7 @@ LL | let [&&x] = &[&mut 0];
194175
| ~
195176

196177
error[E0308]: mismatched types
197-
--> $DIR/pattern-errors.rs:96:11
178+
--> $DIR/pattern-errors.rs:91:11
198179
|
199180
LL | let [&&mut x] = &mut [&mut 0];
200181
| ^^^^^
@@ -206,7 +187,7 @@ LL | let [&&x] = &mut [&mut 0];
206187
| ~
207188

208189
error[E0308]: mismatched types
209-
--> $DIR/pattern-errors.rs:101:11
190+
--> $DIR/pattern-errors.rs:96:11
210191
|
211192
LL | let [&&mut ref x] = &[&mut 0];
212193
| ^^^^^
@@ -218,7 +199,7 @@ LL | let [&&ref x] = &[&mut 0];
218199
| ~
219200

220201
error[E0308]: mismatched types
221-
--> $DIR/pattern-errors.rs:106:11
202+
--> $DIR/pattern-errors.rs:101:11
222203
|
223204
LL | let [&&mut ref x] = &mut [&mut 0];
224205
| ^^^^^
@@ -230,7 +211,7 @@ LL | let [&&ref x] = &mut [&mut 0];
230211
| ~
231212

232213
error[E0308]: mismatched types
233-
--> $DIR/pattern-errors.rs:111:11
214+
--> $DIR/pattern-errors.rs:106:11
234215
|
235216
LL | let [&&mut mut x] = &[&mut 0];
236217
| ^^^^^
@@ -242,7 +223,7 @@ LL | let [&&mut x] = &[&mut 0];
242223
| ~
243224

244225
error[E0308]: mismatched types
245-
--> $DIR/pattern-errors.rs:116:11
226+
--> $DIR/pattern-errors.rs:111:11
246227
|
247228
LL | let [&&mut mut x] = &mut [&mut 0];
248229
| ^^^^^
@@ -253,7 +234,7 @@ help: replace this `&mut` pattern with `&`
253234
LL | let [&&mut x] = &mut [&mut 0];
254235
| ~
255236

256-
error: aborting due to 21 previous errors
237+
error: aborting due to 20 previous errors
257238

258239
Some errors have detailed explanations: E0308, E0658.
259240
For more information about an error, try `rustc --explain E0308`.

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//@ run-pass
44
//! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we
55
//! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests.
6-
#![allow(incomplete_features)]
6+
#![allow(incomplete_features, unused_mut)]
77
#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
88
#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
99

@@ -53,4 +53,27 @@ pub fn main() {
5353
if let Some(&Some(x)) = &mut Some(Some(0)) {
5454
let _: u32 = x;
5555
}
56+
57+
// Tests for eat-inner rulesets matching on the outer reference if matching on the inner
58+
// reference causes a mutability mismatch, i.e. `Deref(EatInner, FallbackToOuter)`:
59+
let [&mut x] = &mut [&0];
60+
let _: &u32 = x;
61+
62+
let [&mut ref x] = &mut [&0];
63+
let _: &&u32 = x;
64+
65+
let [&mut ref mut x] = &mut [&0];
66+
let _: &mut &u32 = x;
67+
68+
let [&mut mut x] = &mut [&0];
69+
let _: &u32 = x;
70+
71+
let [&mut &x] = &mut [&0];
72+
let _: u32 = x;
73+
74+
let [&mut &ref x] = &mut [&0];
75+
let _: &u32 = x;
76+
77+
let [&mut &(mut x)] = &mut [&0];
78+
let _: u32 = x;
5679
}

0 commit comments

Comments
 (0)