Skip to content

Commit a8a74ed

Browse files
committed
"structural2021" ruleset: add fallback-to-outer (eat both) deref rule
1 parent 1ba119c commit a8a74ed

File tree

5 files changed

+151
-179
lines changed

5 files changed

+151
-179
lines changed

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ enum InheritedRefMatchRule {
235235
/// Whether to allow reference patterns to consume only an inherited reference when matching
236236
/// against a non-reference type. This is `false` for stable Rust.
237237
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,
238241
},
239242
}
240243

@@ -261,12 +264,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
261264
} else {
262265
// Currently, matching against an inherited ref on edition 2024 is an error.
263266
// Use `EatBoth` as a fallback to be similar to stable Rust.
264-
InheritedRefMatchRule::EatBoth { eat_inherited_ref_alone: false }
267+
InheritedRefMatchRule::EatBoth {
268+
eat_inherited_ref_alone: false,
269+
fallback_to_outer: false,
270+
}
265271
}
266272
} else {
273+
let has_structural_gate = self.tcx.features().ref_pat_eat_one_layer_2024_structural();
267274
InheritedRefMatchRule::EatBoth {
268-
eat_inherited_ref_alone: self.tcx.features().ref_pat_eat_one_layer_2024()
269-
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
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,
270278
}
271279
}
272280
}
@@ -2386,12 +2394,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23862394
return expected;
23872395
}
23882396
}
2389-
InheritedRefMatchRule::EatBoth { eat_inherited_ref_alone: true } => {
2397+
InheritedRefMatchRule::EatBoth {
2398+
eat_inherited_ref_alone: true,
2399+
fallback_to_outer,
2400+
} => {
23902401
// Reset binding mode on old editions
23912402
pat_info.binding_mode = ByRef::No;
23922403

2393-
if let ty::Ref(_, _, _) = *expected.kind() {
2404+
if let ty::Ref(_, inner_ty, _) = *expected.kind() {
23942405
// Consume both the inherited and inner references.
2406+
if fallback_to_outer && inh_mut.is_mut() {
2407+
// If we can fall back to matching the inherited reference, the expected
2408+
// type is a reference type (of any mutability), and the inherited
2409+
// reference is mutable, we'll always be able to match. We handle that
2410+
// here to avoid adding fallback-to-outer to the common logic below.
2411+
// NB: This way of phrasing the logic will catch more cases than those
2412+
// that need to fall back to matching the inherited reference. However,
2413+
// as long as `&` patterns can match mutable (inherited) references
2414+
// (RFC 3627, Rule 5) this should be sound.
2415+
debug_assert!(ref_pat_matches_mut_ref);
2416+
self.check_pat(inner, inner_ty, pat_info);
2417+
return expected;
2418+
} else {
2419+
// Otherwise, use the common logic below for matching the inner
2420+
// reference type.
2421+
}
23952422
} else {
23962423
// The expected type isn't a reference type, so only match against the
23972424
// inherited reference.
@@ -2405,9 +2432,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24052432
return expected;
24062433
}
24072434
}
2408-
InheritedRefMatchRule::EatBoth { eat_inherited_ref_alone: false } => {
2435+
rule @ InheritedRefMatchRule::EatBoth {
2436+
eat_inherited_ref_alone: false,
2437+
fallback_to_outer,
2438+
} => {
24092439
// Reset binding mode on stable Rust. This will be a type error below if
24102440
// `expected` is not a reference type.
2441+
debug_assert!(!fallback_to_outer, "typing rule `{rule:?}` is unimplemented.");
24112442
pat_info.binding_mode = ByRef::No;
24122443
self.add_rust_2024_migration_desugared_pat(
24132444
pat_info.top_info.hir_id,

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

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -105,28 +105,7 @@ LL + let [ref x] = &mut [&0];
105105
|
106106

107107
error[E0308]: mismatched types
108-
--> $DIR/well-typed-edition-2024.rs:108:10
109-
|
110-
LL | let [&mut ref 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:108:10
119-
|
120-
LL | let [&mut ref mut x] = &mut [&0];
121-
| ^^^^^^^^^^^^^^
122-
help: consider removing `&mut` from the pattern
123-
|
124-
LL - let [&mut ref mut x] = &mut [&0];
125-
LL + let [ref mut x] = &mut [&0];
126-
|
127-
128-
error[E0308]: mismatched types
129-
--> $DIR/well-typed-edition-2024.rs:114:10
108+
--> $DIR/well-typed-edition-2024.rs:117:10
130109
|
131110
LL | let [&mut mut x] = &mut [&0];
132111
| ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -136,7 +115,7 @@ LL | let [&mut mut x] = &mut [&0];
136115
= note: expected reference `&{integer}`
137116
found mutable reference `&mut _`
138117
note: to declare a mutable binding use: `mut x`
139-
--> $DIR/well-typed-edition-2024.rs:114:10
118+
--> $DIR/well-typed-edition-2024.rs:117:10
140119
|
141120
LL | let [&mut mut x] = &mut [&0];
142121
| ^^^^^^^^^^
@@ -147,7 +126,7 @@ LL + let [mut x] = &mut [&0];
147126
|
148127

149128
error[E0308]: mismatched types
150-
--> $DIR/well-typed-edition-2024.rs:120:10
129+
--> $DIR/well-typed-edition-2024.rs:123:10
151130
|
152131
LL | let [&mut &x] = &mut [&0];
153132
| ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -158,7 +137,7 @@ LL | let [&mut &x] = &mut [&0];
158137
found mutable reference `&mut _`
159138

160139
error[E0308]: mismatched types
161-
--> $DIR/well-typed-edition-2024.rs:126:10
140+
--> $DIR/well-typed-edition-2024.rs:129:10
162141
|
163142
LL | let [&mut &ref x] = &mut [&0];
164143
| ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -169,7 +148,7 @@ LL | let [&mut &ref x] = &mut [&0];
169148
found mutable reference `&mut _`
170149

171150
error[E0308]: mismatched types
172-
--> $DIR/well-typed-edition-2024.rs:132:10
151+
--> $DIR/well-typed-edition-2024.rs:135:10
173152
|
174153
LL | let [&mut &(mut x)] = &mut [&0];
175154
| ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -179,6 +158,27 @@ LL | let [&mut &(mut x)] = &mut [&0];
179158
= note: expected reference `&{integer}`
180159
found mutable reference `&mut _`
181160

161+
error[E0308]: mismatched types
162+
--> $DIR/well-typed-edition-2024.rs:109:14
163+
|
164+
LL | let [&mut ref mut x] = &mut [&0];
165+
| ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
166+
| |
167+
| types differ in mutability
168+
|
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
173+
|
174+
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+
|
181+
182182
error: aborting due to 11 previous errors
183183

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

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

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -91,47 +91,50 @@ pub fn main() {
9191
#[cfg(any(classic2024, structural2024))] let _: u32 = x;
9292
}
9393

94-
// Tests for eat-inner rulesets matching on the outer reference if matching on the inner
95-
// reference causes a mutability mismatch, i.e. `Deref(EatInner, FallbackToOuter)`:
94+
// Tests for eat-inner and eat-both rulesets matching on the outer reference if matching on the
95+
// inner reference causes a mutability mismatch. i.e. tests for "fallback-to-outer" deref rules.
9696
let [&mut x] = &mut [&0];
97-
//[stable2021,classic2021,structural2021]~^ mismatched types
98-
//[stable2021,classic2021,structural2021]~| types differ in mutability
99-
// TODO: on `structural2021` `x` should have type `u32`
97+
//[stable2021,classic2021]~^ mismatched types
98+
//[stable2021,classic2021]~| types differ in mutability
99+
#[cfg(structural2021)] let _: u32 = x;
100100
#[cfg(any(classic2024, structural2024))] let _: &u32 = x;
101101

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

108-
let [&mut ref mut x] = &mut [&0];
109-
//[stable2021,classic2021,structural2021]~^ mismatched types
110-
//[stable2021,classic2021,structural2021]~| types differ in mutability
111-
// TODO: this should be a mut borrow behind shared borrow error on `structural2021`
112-
#[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x;
108+
fn borrowck_error_on_structural2021() {
109+
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
113+
#[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x;
114+
}
115+
borrowck_error_on_structural2021();
113116

114117
let [&mut mut x] = &mut [&0];
115-
//[stable2021,classic2021,structural2021]~^ mismatched types
116-
//[stable2021,classic2021,structural2021]~| types differ in mutability
117-
// TODO: on `structural2021` `x` should have type `u32`
118+
//[stable2021,classic2021]~^ mismatched types
119+
//[stable2021,classic2021]~| types differ in mutability
120+
#[cfg(structural2021)] let _: u32 = x;
118121
#[cfg(any(classic2024, structural2024))] let _: &u32 = x;
119122

120123
let [&mut &x] = &mut [&0];
121124
//[stable2021,classic2021,structural2021]~^ mismatched types
122-
//[stable2021,classic2021,structural2021]~| types differ in mutability
123-
// TODO: [structural2021]~| expected integer, found `&_`
125+
//[stable2021,classic2021]~| types differ in mutability
126+
//[structural2021]~| expected integer, found `&_`
124127
#[cfg(any(classic2024, structural2024))] let _: u32 = x;
125128

126129
let [&mut &ref x] = &mut [&0];
127130
//[stable2021,classic2021,structural2021]~^ mismatched types
128-
//[stable2021,classic2021,structural2021]~| types differ in mutability
129-
// TODO: [structural2021]~| expected integer, found `&_`
131+
//[stable2021,classic2021]~| types differ in mutability
132+
//[structural2021]~| expected integer, found `&_`
130133
#[cfg(any(classic2024, structural2024))] let _: &u32 = x;
131134

132135
let [&mut &(mut x)] = &mut [&0];
133136
//[stable2021,classic2021,structural2021]~^ mismatched types
134-
//[stable2021,classic2021,structural2021]~| types differ in mutability
135-
// TODO: [structural2021]~| expected integer, found `&_`
137+
//[stable2021,classic2021]~| types differ in mutability
138+
//[structural2021]~| expected integer, found `&_`
136139
#[cfg(any(classic2024, structural2024))] let _: u32 = x;
137140
}

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

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -186,28 +186,7 @@ LL + let [ref x] = &mut [&0];
186186
|
187187

188188
error[E0308]: mismatched types
189-
--> $DIR/well-typed-edition-2024.rs:108:10
190-
|
191-
LL | let [&mut ref mut x] = &mut [&0];
192-
| ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
193-
| |
194-
| types differ in mutability
195-
|
196-
= note: expected reference `&{integer}`
197-
found mutable reference `&mut _`
198-
note: to declare a mutable binding use: `mut x`
199-
--> $DIR/well-typed-edition-2024.rs:108:10
200-
|
201-
LL | let [&mut ref mut x] = &mut [&0];
202-
| ^^^^^^^^^^^^^^
203-
help: consider removing `&mut` from the pattern
204-
|
205-
LL - let [&mut ref mut x] = &mut [&0];
206-
LL + let [ref mut x] = &mut [&0];
207-
|
208-
209-
error[E0308]: mismatched types
210-
--> $DIR/well-typed-edition-2024.rs:114:10
189+
--> $DIR/well-typed-edition-2024.rs:117:10
211190
|
212191
LL | let [&mut mut x] = &mut [&0];
213192
| ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -217,7 +196,7 @@ LL | let [&mut mut x] = &mut [&0];
217196
= note: expected reference `&{integer}`
218197
found mutable reference `&mut _`
219198
note: to declare a mutable binding use: `mut x`
220-
--> $DIR/well-typed-edition-2024.rs:114:10
199+
--> $DIR/well-typed-edition-2024.rs:117:10
221200
|
222201
LL | let [&mut mut x] = &mut [&0];
223202
| ^^^^^^^^^^
@@ -228,7 +207,7 @@ LL + let [mut x] = &mut [&0];
228207
|
229208

230209
error[E0308]: mismatched types
231-
--> $DIR/well-typed-edition-2024.rs:120:10
210+
--> $DIR/well-typed-edition-2024.rs:123:10
232211
|
233212
LL | let [&mut &x] = &mut [&0];
234213
| ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -239,7 +218,7 @@ LL | let [&mut &x] = &mut [&0];
239218
found mutable reference `&mut _`
240219

241220
error[E0308]: mismatched types
242-
--> $DIR/well-typed-edition-2024.rs:126:10
221+
--> $DIR/well-typed-edition-2024.rs:129:10
243222
|
244223
LL | let [&mut &ref x] = &mut [&0];
245224
| ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -250,7 +229,7 @@ LL | let [&mut &ref x] = &mut [&0];
250229
found mutable reference `&mut _`
251230

252231
error[E0308]: mismatched types
253-
--> $DIR/well-typed-edition-2024.rs:132:10
232+
--> $DIR/well-typed-edition-2024.rs:135:10
254233
|
255234
LL | let [&mut &(mut x)] = &mut [&0];
256235
| ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
@@ -260,6 +239,27 @@ LL | let [&mut &(mut x)] = &mut [&0];
260239
= note: expected reference `&{integer}`
261240
found mutable reference `&mut _`
262241

242+
error[E0308]: mismatched types
243+
--> $DIR/well-typed-edition-2024.rs:109:14
244+
|
245+
LL | let [&mut ref mut x] = &mut [&0];
246+
| ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
247+
| |
248+
| types differ in mutability
249+
|
250+
= note: expected reference `&{integer}`
251+
found mutable reference `&mut _`
252+
note: to declare a mutable binding use: `mut x`
253+
--> $DIR/well-typed-edition-2024.rs:109:14
254+
|
255+
LL | let [&mut ref mut x] = &mut [&0];
256+
| ^^^^^^^^^^^^^^
257+
help: consider removing `&mut` from the pattern
258+
|
259+
LL - let [&mut ref mut x] = &mut [&0];
260+
LL + let [ref mut x] = &mut [&0];
261+
|
262+
263263
error: aborting due to 17 previous errors
264264

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

0 commit comments

Comments
 (0)