Skip to content

Commit 2014962

Browse files
committed
"classic2021" ruleset: experimentally add fallback-to-outer (eat both)
My reasoning: the ruleset implemented by the same feature gate in Edition 2024 always tries to eat the inherited reference first. For consistency, it makes sense to me to say across all editions that users should consider the inherited reference's mutability when wondering if a `&mut` pattern will type.
1 parent 799e0f7 commit 2014962

File tree

4 files changed

+73
-145
lines changed

4 files changed

+73
-145
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+18-28
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,13 @@ enum InheritedRefMatchRule {
232232
/// When the underlying type is a reference type, reference patterns consume both layers of
233233
/// reference, i.e. they both reset the binding mode and consume the reference type.
234234
EatBoth {
235-
/// Whether to allow reference patterns to consume only an inherited reference when matching
236-
/// against a non-reference type. This is `false` for stable Rust.
237-
eat_inherited_ref_alone: bool,
238-
/// Whether to allow a `&mut` reference pattern to eat a `&` reference type if it's also
239-
/// able to consume a mutable inherited reference. This is `false` for stable Rust.
240-
fallback_to_outer: bool,
235+
/// This represents two behaviors implemented by both the `ref_pat_eat_one_layer_2024` and
236+
/// `ref_pat_eat_one_layer_2024_structural` feature gates, and is false for stable Rust.
237+
/// - Whether to allow reference patterns to consume only an inherited reference when
238+
/// matching against a non-reference type.
239+
/// - Whether to allow a `&mut` reference pattern to eat a `&` reference type if it's also
240+
/// able to consume a mutable inherited reference.
241+
consider_inherited_ref_first: bool,
241242
},
242243
}
243244

@@ -264,17 +265,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
264265
} else {
265266
// Currently, matching against an inherited ref on edition 2024 is an error.
266267
// Use `EatBoth` as a fallback to be similar to stable Rust.
267-
InheritedRefMatchRule::EatBoth {
268-
eat_inherited_ref_alone: false,
269-
fallback_to_outer: false,
270-
}
268+
InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false }
271269
}
272270
} else {
273-
let has_structural_gate = self.tcx.features().ref_pat_eat_one_layer_2024_structural();
274271
InheritedRefMatchRule::EatBoth {
275-
eat_inherited_ref_alone: has_structural_gate
276-
|| self.tcx.features().ref_pat_eat_one_layer_2024(),
277-
fallback_to_outer: has_structural_gate,
272+
consider_inherited_ref_first: self.tcx.features().ref_pat_eat_one_layer_2024()
273+
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
278274
}
279275
}
280276
}
@@ -2398,20 +2394,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23982394
return expected;
23992395
}
24002396
}
2401-
InheritedRefMatchRule::EatBoth {
2402-
eat_inherited_ref_alone: true,
2403-
fallback_to_outer,
2404-
} => {
2397+
InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: true } => {
24052398
// Reset binding mode on old editions
24062399
pat_info.binding_mode = ByRef::No;
24072400

24082401
if let ty::Ref(_, inner_ty, _) = *expected.kind() {
24092402
// Consume both the inherited and inner references.
2410-
if fallback_to_outer && inh_mut.is_mut() {
2411-
// If we can fall back to matching the inherited reference, the expected
2412-
// type is a reference type (of any mutability), and the inherited
2413-
// reference is mutable, we'll always be able to match. We handle that
2414-
// here to avoid adding fallback-to-outer to the common logic below.
2403+
if inh_mut.is_mut() {
2404+
// If the expected type is a reference type (of any mutability) and the
2405+
// inherited ref is mutable, we'll be able to match, since we can fall
2406+
// back to matching the inherited ref if the real reference isn't
2407+
// mutable enough for our pattern. We handle that here to avoid adding
2408+
// fallback-to-outer to the common logic below.
24152409
// NB: This way of phrasing the logic will catch more cases than those
24162410
// that need to fall back to matching the inherited reference. However,
24172411
// as long as `&` patterns can match mutable (inherited) references
@@ -2440,13 +2434,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24402434
return expected;
24412435
}
24422436
}
2443-
rule @ InheritedRefMatchRule::EatBoth {
2444-
eat_inherited_ref_alone: false,
2445-
fallback_to_outer,
2446-
} => {
2437+
InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false } => {
24472438
// Reset binding mode on stable Rust. This will be a type error below if
24482439
// `expected` is not a reference type.
2449-
debug_assert!(!fallback_to_outer, "typing rule `{rule:?}` is unimplemented.");
24502440
pat_info.binding_mode = ByRef::No;
24512441
self.add_rust_2024_migration_desugared_pat(
24522442
pat_info.top_info.hir_id,

src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ For more information, see the corresponding typing rules for [Editions 2021 and
1616
For alternative experimental match ergonomics, see the feature
1717
[`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md).
1818

19-
[Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQABAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false
19+
[Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false
2020
[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false

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

+36-98
Original file line numberDiff line numberDiff line change
@@ -63,122 +63,60 @@ LL + if let Some(&Some(x)) = &mut Some(&Some(0)) {
6363
|
6464

6565
error[E0308]: mismatched types
66-
--> $DIR/well-typed-edition-2024.rs:96:10
66+
--> $DIR/well-typed-edition-2024.rs:123:15
6767
|
68-
LL | let [&mut x] = &mut [&0];
69-
| ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
70-
| |
71-
| types differ in mutability
72-
|
73-
= note: expected reference `&{integer}`
74-
found mutable reference `&mut _`
75-
note: to declare a mutable binding use: `mut x`
76-
--> $DIR/well-typed-edition-2024.rs:96:10
77-
|
78-
LL | let [&mut x] = &mut [&0];
79-
| ^^^^^^
80-
help: consider removing `&mut` from the pattern
81-
|
82-
LL - let [&mut x] = &mut [&0];
83-
LL + let [x] = &mut [&0];
84-
|
85-
86-
error[E0308]: mismatched types
87-
--> $DIR/well-typed-edition-2024.rs:102:10
88-
|
89-
LL | let [&mut ref x] = &mut [&0];
90-
| ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
91-
| |
92-
| types differ in mutability
93-
|
94-
= note: expected reference `&{integer}`
95-
found mutable reference `&mut _`
96-
note: to declare a mutable binding use: `mut x`
97-
--> $DIR/well-typed-edition-2024.rs:102:10
98-
|
99-
LL | let [&mut ref x] = &mut [&0];
100-
| ^^^^^^^^^^
101-
help: consider removing `&mut` from the pattern
102-
|
103-
LL - let [&mut ref x] = &mut [&0];
104-
LL + let [ref x] = &mut [&0];
105-
|
106-
107-
error[E0308]: mismatched types
108-
--> $DIR/well-typed-edition-2024.rs:117:10
109-
|
110-
LL | let [&mut mut x] = &mut [&0];
111-
| ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
112-
| |
113-
| types differ in mutability
114-
|
115-
= note: expected reference `&{integer}`
116-
found mutable reference `&mut _`
117-
note: to declare a mutable binding use: `mut x`
118-
--> $DIR/well-typed-edition-2024.rs:117:10
68+
LL | let [&mut &x] = &mut [&0];
69+
| ^^ --------- this expression has type `&mut [&{integer}; 1]`
70+
| |
71+
| expected integer, found `&_`
11972
|
120-
LL | let [&mut mut x] = &mut [&0];
121-
| ^^^^^^^^^^
122-
help: consider removing `&mut` from the pattern
73+
= note: expected type `{integer}`
74+
found reference `&_`
75+
help: consider removing `&` from the pattern
12376
|
124-
LL - let [&mut mut x] = &mut [&0];
125-
LL + let [mut x] = &mut [&0];
77+
LL - let [&mut &x] = &mut [&0];
78+
LL + let [&mut x] = &mut [&0];
12679
|
12780

12881
error[E0308]: mismatched types
129-
--> $DIR/well-typed-edition-2024.rs:123:10
82+
--> $DIR/well-typed-edition-2024.rs:129:15
13083
|
131-
LL | let [&mut &x] = &mut [&0];
132-
| ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
133-
| |
134-
| types differ in mutability
84+
LL | let [&mut &ref x] = &mut [&0];
85+
| ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
86+
| |
87+
| expected integer, found `&_`
13588
|
136-
= note: expected reference `&{integer}`
137-
found mutable reference `&mut _`
138-
139-
error[E0308]: mismatched types
140-
--> $DIR/well-typed-edition-2024.rs:129:10
89+
= note: expected type `{integer}`
90+
found reference `&_`
91+
help: consider removing `&` from the pattern
14192
|
142-
LL | let [&mut &ref x] = &mut [&0];
143-
| ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
144-
| |
145-
| types differ in mutability
93+
LL - let [&mut &ref x] = &mut [&0];
94+
LL + let [&mut ref x] = &mut [&0];
14695
|
147-
= note: expected reference `&{integer}`
148-
found mutable reference `&mut _`
14996

15097
error[E0308]: mismatched types
151-
--> $DIR/well-typed-edition-2024.rs:135:10
98+
--> $DIR/well-typed-edition-2024.rs:135:15
15299
|
153100
LL | let [&mut &(mut x)] = &mut [&0];
154-
| ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
155-
| |
156-
| types differ in mutability
101+
| ^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
102+
| |
103+
| expected integer, found `&_`
157104
|
158-
= note: expected reference `&{integer}`
159-
found mutable reference `&mut _`
160-
161-
error[E0308]: mismatched types
162-
--> $DIR/well-typed-edition-2024.rs:109:14
105+
= note: expected type `{integer}`
106+
found reference `&_`
107+
help: consider removing `&` from the pattern
163108
|
164-
LL | let [&mut ref mut x] = &mut [&0];
165-
| ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
166-
| |
167-
| types differ in mutability
109+
LL - let [&mut &(mut x)] = &mut [&0];
110+
LL + let [&mut mut x)] = &mut [&0];
168111
|
169-
= note: expected reference `&{integer}`
170-
found mutable reference `&mut _`
171-
note: to declare a mutable binding use: `mut x`
172-
--> $DIR/well-typed-edition-2024.rs:109:14
112+
113+
error[E0596]: cannot borrow data in a `&` reference as mutable
114+
--> $DIR/well-typed-edition-2024.rs:109:19
173115
|
174116
LL | let [&mut ref mut x] = &mut [&0];
175-
| ^^^^^^^^^^^^^^
176-
help: consider removing `&mut` from the pattern
177-
|
178-
LL - let [&mut ref mut x] = &mut [&0];
179-
LL + let [ref mut x] = &mut [&0];
180-
|
117+
| ^^^^^^^^^ cannot borrow as mutable
181118

182-
error: aborting due to 11 previous errors
119+
error: aborting due to 8 previous errors
183120

184-
For more information about this error, try `rustc --explain E0308`.
121+
Some errors have detailed explanations: E0308, E0596.
122+
For more information about an error, try `rustc --explain E0308`.

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

+18-18
Original file line numberDiff line numberDiff line change
@@ -94,47 +94,47 @@ pub fn main() {
9494
// Tests for eat-inner and eat-both rulesets matching on the outer reference if matching on the
9595
// inner reference causes a mutability mismatch. i.e. tests for "fallback-to-outer" deref rules.
9696
let [&mut x] = &mut [&0];
97-
//[stable2021,classic2021]~^ mismatched types
98-
//[stable2021,classic2021]~| types differ in mutability
99-
#[cfg(structural2021)] let _: u32 = x;
97+
//[stable2021]~^ mismatched types
98+
//[stable2021]~| types differ in mutability
99+
#[cfg(any(classic2021, structural2021))] let _: u32 = x;
100100
#[cfg(any(classic2024, structural2024))] let _: &u32 = x;
101101

102102
let [&mut ref x] = &mut [&0];
103-
//[stable2021,classic2021]~^ mismatched types
104-
//[stable2021,classic2021]~| types differ in mutability
105-
#[cfg(structural2021)] let _: &u32 = x;
103+
//[stable2021]~^ mismatched types
104+
//[stable2021]~| types differ in mutability
105+
#[cfg(any(classic2021, structural2021))] let _: &u32 = x;
106106
#[cfg(any(classic2024, structural2024))] let _: &&u32 = x;
107107

108108
fn borrowck_error_on_structural2021() {
109109
let [&mut ref mut x] = &mut [&0];
110-
//[stable2021,classic2021]~^ mismatched types
111-
//[stable2021,classic2021]~| types differ in mutability
112-
//[structural2021]~^^^ cannot borrow data in a `&` reference as mutable
110+
//[stable2021]~^ mismatched types
111+
//[stable2021]~| types differ in mutability
112+
//[classic2021,structural2021]~^^^ cannot borrow data in a `&` reference as mutable
113113
#[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x;
114114
}
115115
borrowck_error_on_structural2021();
116116

117117
let [&mut mut x] = &mut [&0];
118-
//[stable2021,classic2021]~^ mismatched types
119-
//[stable2021,classic2021]~| types differ in mutability
120-
#[cfg(structural2021)] let _: u32 = x;
118+
//[stable2021]~^ mismatched types
119+
//[stable2021]~| types differ in mutability
120+
#[cfg(any(classic2021, structural2021))] let _: u32 = x;
121121
#[cfg(any(classic2024, structural2024))] let _: &u32 = x;
122122

123123
let [&mut &x] = &mut [&0];
124124
//[stable2021,classic2021,structural2021]~^ mismatched types
125-
//[stable2021,classic2021]~| types differ in mutability
126-
//[structural2021]~| expected integer, found `&_`
125+
//[stable2021]~| types differ in mutability
126+
//[classic2021,structural2021]~| expected integer, found `&_`
127127
#[cfg(any(classic2024, structural2024))] let _: u32 = x;
128128

129129
let [&mut &ref x] = &mut [&0];
130130
//[stable2021,classic2021,structural2021]~^ mismatched types
131-
//[stable2021,classic2021]~| types differ in mutability
132-
//[structural2021]~| expected integer, found `&_`
131+
//[stable2021]~| types differ in mutability
132+
//[classic2021,structural2021]~| expected integer, found `&_`
133133
#[cfg(any(classic2024, structural2024))] let _: &u32 = x;
134134

135135
let [&mut &(mut x)] = &mut [&0];
136136
//[stable2021,classic2021,structural2021]~^ mismatched types
137-
//[stable2021,classic2021]~| types differ in mutability
138-
//[structural2021]~| expected integer, found `&_`
137+
//[stable2021]~| types differ in mutability
138+
//[classic2021,structural2021]~| expected integer, found `&_`
139139
#[cfg(any(classic2024, structural2024))] let _: u32 = x;
140140
}

0 commit comments

Comments
 (0)