"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.
This commit is contained in:
dianne 2025-01-26 04:20:30 -08:00
parent 799e0f7690
commit 20149629ba
4 changed files with 76 additions and 148 deletions

View File

@ -232,12 +232,13 @@ enum InheritedRefMatchRule {
/// When the underlying type is a reference type, reference patterns consume both layers of /// When the underlying type is a reference type, reference patterns consume both layers of
/// reference, i.e. they both reset the binding mode and consume the reference type. /// reference, i.e. they both reset the binding mode and consume the reference type.
EatBoth { EatBoth {
/// Whether to allow reference patterns to consume only an inherited reference when matching /// This represents two behaviors implemented by both the `ref_pat_eat_one_layer_2024` and
/// against a non-reference type. This is `false` for stable Rust. /// `ref_pat_eat_one_layer_2024_structural` feature gates, and is false for stable Rust.
eat_inherited_ref_alone: bool, /// - Whether to allow reference patterns to consume only an inherited reference when
/// Whether to allow a `&mut` reference pattern to eat a `&` reference type if it's also /// matching against a non-reference type.
/// able to consume a mutable inherited reference. This is `false` for stable Rust. /// - Whether to allow a `&mut` reference pattern to eat a `&` reference type if it's also
fallback_to_outer: bool, /// able to consume a mutable inherited reference.
consider_inherited_ref_first: bool,
}, },
} }
@ -264,17 +265,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else { } else {
// Currently, matching against an inherited ref on edition 2024 is an error. // Currently, matching against an inherited ref on edition 2024 is an error.
// Use `EatBoth` as a fallback to be similar to stable Rust. // Use `EatBoth` as a fallback to be similar to stable Rust.
InheritedRefMatchRule::EatBoth { InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false }
eat_inherited_ref_alone: false,
fallback_to_outer: false,
}
} }
} else { } else {
let has_structural_gate = self.tcx.features().ref_pat_eat_one_layer_2024_structural();
InheritedRefMatchRule::EatBoth { InheritedRefMatchRule::EatBoth {
eat_inherited_ref_alone: has_structural_gate consider_inherited_ref_first: self.tcx.features().ref_pat_eat_one_layer_2024()
|| self.tcx.features().ref_pat_eat_one_layer_2024(), || self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
fallback_to_outer: has_structural_gate,
} }
} }
} }
@ -2398,20 +2394,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return expected; return expected;
} }
} }
InheritedRefMatchRule::EatBoth { InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: true } => {
eat_inherited_ref_alone: true,
fallback_to_outer,
} => {
// Reset binding mode on old editions // Reset binding mode on old editions
pat_info.binding_mode = ByRef::No; pat_info.binding_mode = ByRef::No;
if let ty::Ref(_, inner_ty, _) = *expected.kind() { if let ty::Ref(_, inner_ty, _) = *expected.kind() {
// Consume both the inherited and inner references. // Consume both the inherited and inner references.
if fallback_to_outer && inh_mut.is_mut() { if inh_mut.is_mut() {
// If we can fall back to matching the inherited reference, the expected // If the expected type is a reference type (of any mutability) and the
// type is a reference type (of any mutability), and the inherited // inherited ref is mutable, we'll be able to match, since we can fall
// reference is mutable, we'll always be able to match. We handle that // back to matching the inherited ref if the real reference isn't
// here to avoid adding fallback-to-outer to the common logic below. // mutable enough for our pattern. We handle that here to avoid adding
// fallback-to-outer to the common logic below.
// NB: This way of phrasing the logic will catch more cases than those // NB: This way of phrasing the logic will catch more cases than those
// that need to fall back to matching the inherited reference. However, // that need to fall back to matching the inherited reference. However,
// as long as `&` patterns can match mutable (inherited) references // as long as `&` patterns can match mutable (inherited) references
@ -2440,13 +2434,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return expected; return expected;
} }
} }
rule @ InheritedRefMatchRule::EatBoth { InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false } => {
eat_inherited_ref_alone: false,
fallback_to_outer,
} => {
// Reset binding mode on stable Rust. This will be a type error below if // Reset binding mode on stable Rust. This will be a type error below if
// `expected` is not a reference type. // `expected` is not a reference type.
debug_assert!(!fallback_to_outer, "typing rule `{rule:?}` is unimplemented.");
pat_info.binding_mode = ByRef::No; pat_info.binding_mode = ByRef::No;
self.add_rust_2024_migration_desugared_pat( self.add_rust_2024_migration_desugared_pat(
pat_info.top_info.hir_id, pat_info.top_info.hir_id,

View File

@ -16,5 +16,5 @@ For more information, see the corresponding typing rules for [Editions 2021 and
For alternative experimental match ergonomics, see the feature For alternative experimental match ergonomics, see the feature
[`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md). [`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md).
[Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQABAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false [Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false
[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false

View File

@ -63,122 +63,60 @@ LL + if let Some(&Some(x)) = &mut Some(&Some(0)) {
| |
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/well-typed-edition-2024.rs:96:10 --> $DIR/well-typed-edition-2024.rs:123:15
|
LL | let [&mut x] = &mut [&0];
| ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
| |
| types differ in mutability
|
= note: expected reference `&{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/well-typed-edition-2024.rs:96:10
|
LL | let [&mut x] = &mut [&0];
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL - let [&mut x] = &mut [&0];
LL + let [x] = &mut [&0];
|
error[E0308]: mismatched types
--> $DIR/well-typed-edition-2024.rs:102:10
|
LL | let [&mut ref x] = &mut [&0];
| ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
| |
| types differ in mutability
|
= note: expected reference `&{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/well-typed-edition-2024.rs:102:10
|
LL | let [&mut ref x] = &mut [&0];
| ^^^^^^^^^^
help: consider removing `&mut` from the pattern
|
LL - let [&mut ref x] = &mut [&0];
LL + let [ref x] = &mut [&0];
|
error[E0308]: mismatched types
--> $DIR/well-typed-edition-2024.rs:117:10
|
LL | let [&mut mut x] = &mut [&0];
| ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
| |
| types differ in mutability
|
= note: expected reference `&{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/well-typed-edition-2024.rs:117:10
|
LL | let [&mut mut x] = &mut [&0];
| ^^^^^^^^^^
help: consider removing `&mut` from the pattern
|
LL - let [&mut mut x] = &mut [&0];
LL + let [mut x] = &mut [&0];
|
error[E0308]: mismatched types
--> $DIR/well-typed-edition-2024.rs:123:10
| |
LL | let [&mut &x] = &mut [&0]; LL | let [&mut &x] = &mut [&0];
| ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` | ^^ --------- this expression has type `&mut [&{integer}; 1]`
| | | |
| types differ in mutability | expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let [&mut &x] = &mut [&0];
LL + let [&mut x] = &mut [&0];
| |
= note: expected reference `&{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/well-typed-edition-2024.rs:129:10 --> $DIR/well-typed-edition-2024.rs:129:15
| |
LL | let [&mut &ref x] = &mut [&0]; LL | let [&mut &ref x] = &mut [&0];
| ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` | ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
| | | |
| types differ in mutability | expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let [&mut &ref x] = &mut [&0];
LL + let [&mut ref x] = &mut [&0];
| |
= note: expected reference `&{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/well-typed-edition-2024.rs:135:10 --> $DIR/well-typed-edition-2024.rs:135:15
| |
LL | let [&mut &(mut x)] = &mut [&0]; LL | let [&mut &(mut x)] = &mut [&0];
| ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` | ^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]`
| | | |
| types differ in mutability | expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let [&mut &(mut x)] = &mut [&0];
LL + let [&mut mut x)] = &mut [&0];
| |
= note: expected reference `&{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/well-typed-edition-2024.rs:109:14 --> $DIR/well-typed-edition-2024.rs:109:19
| |
LL | let [&mut ref mut x] = &mut [&0]; LL | let [&mut ref mut x] = &mut [&0];
| ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` | ^^^^^^^^^ cannot borrow as mutable
| |
| types differ in mutability
|
= note: expected reference `&{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/well-typed-edition-2024.rs:109:14
|
LL | let [&mut ref mut x] = &mut [&0];
| ^^^^^^^^^^^^^^
help: consider removing `&mut` from the pattern
|
LL - let [&mut ref mut x] = &mut [&0];
LL + let [ref mut x] = &mut [&0];
|
error: aborting due to 11 previous errors error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0308`. Some errors have detailed explanations: E0308, E0596.
For more information about an error, try `rustc --explain E0308`.

View File

@ -94,47 +94,47 @@ pub fn main() {
// Tests for eat-inner and eat-both rulesets matching on the outer reference if matching on the // Tests for eat-inner and eat-both rulesets matching on the outer reference if matching on the
// inner reference causes a mutability mismatch. i.e. tests for "fallback-to-outer" deref rules. // inner reference causes a mutability mismatch. i.e. tests for "fallback-to-outer" deref rules.
let [&mut x] = &mut [&0]; let [&mut x] = &mut [&0];
//[stable2021,classic2021]~^ mismatched types //[stable2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
#[cfg(structural2021)] let _: u32 = x; #[cfg(any(classic2021, structural2021))] let _: u32 = x;
#[cfg(any(classic2024, structural2024))] let _: &u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x;
let [&mut ref x] = &mut [&0]; let [&mut ref x] = &mut [&0];
//[stable2021,classic2021]~^ mismatched types //[stable2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
#[cfg(structural2021)] let _: &u32 = x; #[cfg(any(classic2021, structural2021))] let _: &u32 = x;
#[cfg(any(classic2024, structural2024))] let _: &&u32 = x; #[cfg(any(classic2024, structural2024))] let _: &&u32 = x;
fn borrowck_error_on_structural2021() { fn borrowck_error_on_structural2021() {
let [&mut ref mut x] = &mut [&0]; let [&mut ref mut x] = &mut [&0];
//[stable2021,classic2021]~^ mismatched types //[stable2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
//[structural2021]~^^^ cannot borrow data in a `&` reference as mutable //[classic2021,structural2021]~^^^ cannot borrow data in a `&` reference as mutable
#[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x; #[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x;
} }
borrowck_error_on_structural2021(); borrowck_error_on_structural2021();
let [&mut mut x] = &mut [&0]; let [&mut mut x] = &mut [&0];
//[stable2021,classic2021]~^ mismatched types //[stable2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
#[cfg(structural2021)] let _: u32 = x; #[cfg(any(classic2021, structural2021))] let _: u32 = x;
#[cfg(any(classic2024, structural2024))] let _: &u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x;
let [&mut &x] = &mut [&0]; let [&mut &x] = &mut [&0];
//[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021,classic2021,structural2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
//[structural2021]~| expected integer, found `&_` //[classic2021,structural2021]~| expected integer, found `&_`
#[cfg(any(classic2024, structural2024))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: u32 = x;
let [&mut &ref x] = &mut [&0]; let [&mut &ref x] = &mut [&0];
//[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021,classic2021,structural2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
//[structural2021]~| expected integer, found `&_` //[classic2021,structural2021]~| expected integer, found `&_`
#[cfg(any(classic2024, structural2024))] let _: &u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x;
let [&mut &(mut x)] = &mut [&0]; let [&mut &(mut x)] = &mut [&0];
//[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021,classic2021,structural2021]~^ mismatched types
//[stable2021,classic2021]~| types differ in mutability //[stable2021]~| types differ in mutability
//[structural2021]~| expected integer, found `&_` //[classic2021,structural2021]~| expected integer, found `&_`
#[cfg(any(classic2024, structural2024))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: u32 = x;
} }