Skip to content

Commit 4b7c080

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 29626d0 commit 4b7c080

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
}
@@ -2390,20 +2386,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23902386
return expected;
23912387
}
23922388
}
2393-
InheritedRefMatchRule::EatBoth {
2394-
eat_inherited_ref_alone: true,
2395-
fallback_to_outer,
2396-
} => {
2389+
InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: true } => {
23972390
// Reset binding mode on old editions
23982391
pat_info.binding_mode = ByRef::No;
23992392

24002393
if let ty::Ref(_, inner_ty, _) = *expected.kind() {
24012394
// Consume both the inherited and inner references.
2402-
if fallback_to_outer && inh_mut.is_mut() {
2403-
// If we can fall back to matching the inherited reference, the expected
2404-
// type is a reference type (of any mutability), and the inherited
2405-
// reference is mutable, we'll always be able to match. We handle that
2406-
// here to avoid adding fallback-to-outer to the common logic below.
2395+
if inh_mut.is_mut() {
2396+
// If the expected type is a reference type (of any mutability) and the
2397+
// inherited ref is mutable, we'll be able to match, since we can fall
2398+
// back to matching the inherited ref if the real reference isn't
2399+
// mutable enough for our pattern. We handle that here to avoid adding
2400+
// fallback-to-outer to the common logic below.
24072401
// NB: This way of phrasing the logic will catch more cases than those
24082402
// that need to fall back to matching the inherited reference. However,
24092403
// as long as `&` patterns can match mutable (inherited) references
@@ -2432,13 +2426,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24322426
return expected;
24332427
}
24342428
}
2435-
rule @ InheritedRefMatchRule::EatBoth {
2436-
eat_inherited_ref_alone: false,
2437-
fallback_to_outer,
2438-
} => {
2429+
InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false } => {
24392430
// Reset binding mode on stable Rust. This will be a type error below if
24402431
// `expected` is not a reference type.
2441-
debug_assert!(!fallback_to_outer, "typing rule `{rule:?}` is unimplemented.");
24422432
pat_info.binding_mode = ByRef::No;
24432433
self.add_rust_2024_migration_desugared_pat(
24442434
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
@@ -60,122 +60,60 @@ LL | if let Some(&Some(x)) = &mut Some(&Some(0)) {
6060
| ~
6161

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

12578
error[E0308]: mismatched types
126-
--> $DIR/well-typed-edition-2024.rs:123:10
79+
--> $DIR/well-typed-edition-2024.rs:129:15
12780
|
128-
LL | let [&mut &x] = &mut [&0];
129-
| ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
130-
| |
131-
| types differ in mutability
81+
LL | let [&mut &ref x] = &mut [&0];
82+
| ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
83+
| |
84+
| expected integer, found `&_`
13285
|
133-
= note: expected reference `&{integer}`
134-
found mutable reference `&mut _`
135-
136-
error[E0308]: mismatched types
137-
--> $DIR/well-typed-edition-2024.rs:129:10
86+
= note: expected type `{integer}`
87+
found reference `&_`
88+
help: consider removing `&` from the pattern
13889
|
139-
LL | let [&mut &ref x] = &mut [&0];
140-
| ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
141-
| |
142-
| types differ in mutability
90+
LL - let [&mut &ref x] = &mut [&0];
91+
LL + let [&mut ref x] = &mut [&0];
14392
|
144-
= note: expected reference `&{integer}`
145-
found mutable reference `&mut _`
14693

14794
error[E0308]: mismatched types
148-
--> $DIR/well-typed-edition-2024.rs:135:10
95+
--> $DIR/well-typed-edition-2024.rs:135:15
14996
|
15097
LL | let [&mut &(mut x)] = &mut [&0];
151-
| ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
152-
| |
153-
| types differ in mutability
98+
| ^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
99+
| |
100+
| expected integer, found `&_`
154101
|
155-
= note: expected reference `&{integer}`
156-
found mutable reference `&mut _`
157-
158-
error[E0308]: mismatched types
159-
--> $DIR/well-typed-edition-2024.rs:109:14
102+
= note: expected type `{integer}`
103+
found reference `&_`
104+
help: consider removing `&` from the pattern
160105
|
161-
LL | let [&mut ref mut x] = &mut [&0];
162-
| ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
163-
| |
164-
| types differ in mutability
106+
LL - let [&mut &(mut x)] = &mut [&0];
107+
LL + let [&mut mut x)] = &mut [&0];
165108
|
166-
= note: expected reference `&{integer}`
167-
found mutable reference `&mut _`
168-
note: to declare a mutable binding use: `mut x`
169-
--> $DIR/well-typed-edition-2024.rs:109:14
109+
110+
error[E0596]: cannot borrow data in a `&` reference as mutable
111+
--> $DIR/well-typed-edition-2024.rs:109:19
170112
|
171113
LL | let [&mut ref mut x] = &mut [&0];
172-
| ^^^^^^^^^^^^^^
173-
help: consider removing `&mut` from the pattern
174-
|
175-
LL - let [&mut ref mut x] = &mut [&0];
176-
LL + let [ref mut x] = &mut [&0];
177-
|
114+
| ^^^^^^^^^ cannot borrow as mutable
178115

179-
error: aborting due to 11 previous errors
116+
error: aborting due to 8 previous errors
180117

181-
For more information about this error, try `rustc --explain E0308`.
118+
Some errors have detailed explanations: E0308, E0596.
119+
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)