about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs46
-rw-r--r--src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md2
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr134
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs36
4 files changed, 73 insertions, 145 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
+  --> $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 &x] = &mut [&0];
+   |               ^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |               |
+   |               expected integer, found `&_`
    |
-LL |     let [&mut mut x] = &mut [&0];
-   |          ^^^^^^^^^^
-help: consider removing `&mut` from the pattern
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
    |
-LL -     let [&mut mut x] = &mut [&0];
-LL +     let [mut x] = &mut [&0];
+LL -     let [&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:129:15
    |
-LL |     let [&mut &x] = &mut [&0];
-   |          ^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
-   |          |
-   |          types differ in mutability
+LL |     let [&mut &ref x] = &mut [&0];
+   |               ^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |               |
+   |               expected integer, found `&_`
    |
-   = note:      expected reference `&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/well-typed-edition-2024.rs:129:10
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
    |
-LL |     let [&mut &ref x] = &mut [&0];
-   |          ^^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
-   |          |
-   |          types differ in mutability
+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 reference `&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/well-typed-edition-2024.rs:109:14
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
    |
-LL |         let [&mut ref mut x] = &mut [&0];
-   |              ^^^^^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
-   |              |
-   |              types differ in mutability
+LL -     let [&mut &(mut x)] = &mut [&0];
+LL +     let [&mut mut x)] = &mut [&0];
    |
-   = 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
+
+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];
-   |              ^^^^^^^^^^^^^^
-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;
 }