From 20149629ba8b143f0529295be22450488e173f30 Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 26 Jan 2025 04:20:30 -0800 Subject: [PATCH] "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. --- compiler/rustc_hir_typeck/src/pat.rs | 46 +++--- .../ref-pat-eat-one-layer-2024.md | 2 +- ...well-typed-edition-2024.classic2021.stderr | 140 +++++------------- .../experimental/well-typed-edition-2024.rs | 36 ++--- 4 files changed, 76 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 1e28571807e..4201ef66741 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -232,12 +232,13 @@ enum InheritedRefMatchRule { /// 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. EatBoth { - /// Whether to allow reference patterns to consume only an inherited reference when matching - /// against a non-reference type. This is `false` for stable Rust. - eat_inherited_ref_alone: bool, - /// Whether to allow a `&mut` reference pattern to eat a `&` reference type if it's also - /// able to consume a mutable inherited reference. This is `false` for stable Rust. - fallback_to_outer: bool, + /// This represents two behaviors implemented by both the `ref_pat_eat_one_layer_2024` and + /// `ref_pat_eat_one_layer_2024_structural` feature gates, and is false for stable Rust. + /// - Whether to allow reference patterns to consume only an inherited reference when + /// matching against a non-reference type. + /// - Whether to allow a `&mut` reference pattern to eat a `&` reference type if it's also + /// able to consume a mutable inherited reference. + consider_inherited_ref_first: bool, }, } @@ -264,17 +265,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Currently, matching against an inherited ref on edition 2024 is an error. // Use `EatBoth` as a fallback to be similar to stable Rust. - InheritedRefMatchRule::EatBoth { - eat_inherited_ref_alone: false, - fallback_to_outer: false, - } + InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false } } } else { - let has_structural_gate = self.tcx.features().ref_pat_eat_one_layer_2024_structural(); InheritedRefMatchRule::EatBoth { - eat_inherited_ref_alone: has_structural_gate - || self.tcx.features().ref_pat_eat_one_layer_2024(), - fallback_to_outer: 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_structural(), } } } @@ -2398,20 +2394,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return expected; } } - InheritedRefMatchRule::EatBoth { - eat_inherited_ref_alone: true, - fallback_to_outer, - } => { + InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: true } => { // Reset binding mode on old editions pat_info.binding_mode = ByRef::No; if let ty::Ref(_, inner_ty, _) = *expected.kind() { // Consume both the inherited and inner references. - if fallback_to_outer && inh_mut.is_mut() { - // If we can fall back to matching the inherited reference, the expected - // type is a reference type (of any mutability), and the inherited - // reference is mutable, we'll always be able to match. We handle that - // here to avoid adding fallback-to-outer to the common logic below. + if inh_mut.is_mut() { + // If the expected type is a reference type (of any mutability) and the + // inherited ref is mutable, we'll be able to match, since we can fall + // back to matching the inherited ref if the real reference isn't + // 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 // that need to fall back to matching the inherited reference. However, // as long as `&` patterns can match mutable (inherited) references @@ -2440,13 +2434,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return expected; } } - rule @ InheritedRefMatchRule::EatBoth { - eat_inherited_ref_alone: false, - fallback_to_outer, - } => { + InheritedRefMatchRule::EatBoth { consider_inherited_ref_first: false } => { // Reset binding mode on stable Rust. This will be a type error below if // `expected` is not a reference type. - debug_assert!(!fallback_to_outer, "typing rule `{rule:?}` is unimplemented."); pat_info.binding_mode = ByRef::No; self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md index 58d8d290503..0c90cec0dbd 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md @@ -16,5 +16,5 @@ For more information, see the corresponding typing rules for [Editions 2021 and For alternative experimental match ergonomics, see the feature [`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 diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr index 086d4bb133b..f8c2bd9a921 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr @@ -63,122 +63,60 @@ LL + if let Some(&Some(x)) = &mut Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:96:10 - | -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 + --> $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 + | ^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | 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 - --> $DIR/well-typed-edition-2024.rs:129:10 + --> $DIR/well-typed-edition-2024.rs:129:15 | LL | let [&mut &ref x] = &mut [&0]; - | ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` - | | - | types differ in mutability + | ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | 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 - --> $DIR/well-typed-edition-2024.rs:135:10 + --> $DIR/well-typed-edition-2024.rs:135:15 | LL | let [&mut &(mut x)] = &mut [&0]; - | ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` - | | - | types differ in mutability + | ^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | 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 - --> $DIR/well-typed-edition-2024.rs:109:14 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/well-typed-edition-2024.rs:109:19 | LL | let [&mut ref 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: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]; - | + | ^^^^^^^^^ cannot borrow as mutable -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`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs index 63a09fe90c9..62c1c28022b 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs @@ -94,47 +94,47 @@ pub fn main() { // 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. let [&mut x] = &mut [&0]; - //[stable2021,classic2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - #[cfg(structural2021)] let _: u32 = x; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + #[cfg(any(classic2021, structural2021))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut ref x] = &mut [&0]; - //[stable2021,classic2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - #[cfg(structural2021)] let _: &u32 = x; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + #[cfg(any(classic2021, structural2021))] let _: &u32 = x; #[cfg(any(classic2024, structural2024))] let _: &&u32 = x; fn borrowck_error_on_structural2021() { let [&mut ref mut x] = &mut [&0]; - //[stable2021,classic2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - //[structural2021]~^^^ cannot borrow data in a `&` reference as mutable + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + //[classic2021,structural2021]~^^^ cannot borrow data in a `&` reference as mutable #[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x; } borrowck_error_on_structural2021(); let [&mut mut x] = &mut [&0]; - //[stable2021,classic2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - #[cfg(structural2021)] let _: u32 = x; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + #[cfg(any(classic2021, structural2021))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut &x] = &mut [&0]; //[stable2021,classic2021,structural2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - //[structural2021]~| expected integer, found `&_` + //[stable2021]~| types differ in mutability + //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; let [&mut &ref x] = &mut [&0]; //[stable2021,classic2021,structural2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - //[structural2021]~| expected integer, found `&_` + //[stable2021]~| types differ in mutability + //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut &(mut x)] = &mut [&0]; //[stable2021,classic2021,structural2021]~^ mismatched types - //[stable2021,classic2021]~| types differ in mutability - //[structural2021]~| expected integer, found `&_` + //[stable2021]~| types differ in mutability + //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; }