about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJules Bertholet <julesbertholet@quoi.xyz>2024-03-31 22:27:19 -0500
committerJules Bertholet <julesbertholet@quoi.xyz>2024-04-15 23:34:44 -0400
commit93544d5db3d8f0d0e5d2ea344154689008fa2ff8 (patch)
tree0b499c2f52cde77703a03bdd550b6307353ea446
parent63f70b3d104e20289a1a0df82747066c3d85b9a1 (diff)
downloadrust-93544d5db3d8f0d0e5d2ea344154689008fa2ff8.tar.gz
rust-93544d5db3d8f0d0e5d2ea344154689008fa2ff8.zip
Match ergonomics 2024: Implement eat-one-layer
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs120
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs37
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr128
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs37
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr128
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs32
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs13
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr25
10 files changed, 472 insertions, 51 deletions
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e6b19817de3..5d17675a532 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -571,6 +571,8 @@ declare_features! (
     (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (unstable, raw_ref_op, "1.41.0", Some(64490)),
+    /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
+    (incomplete, ref_pat_eat_one_layer_2024, "CURRENT_RUSTC_VERSION", Some(123076)),
     /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
     (incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
     /// Allows using the `#[register_tool]` attribute.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index db4bd132b7e..ff7716ce7ea 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -294,7 +294,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             AdjustMode::Pass => (expected, def_bm, false),
             AdjustMode::Reset => (expected, INITIAL_BM, false),
             AdjustMode::ResetAndConsumeRef(mutbl) => {
-                (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl))
+                let mutbls_match = def_bm.0 == ByRef::Yes(mutbl);
+                if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
+                    if mutbls_match {
+                        (expected, INITIAL_BM, true)
+                    } else {
+                        (expected, def_bm, false)
+                    }
+                } else {
+                    (expected, INITIAL_BM, mutbls_match)
+                }
             }
             AdjustMode::Peel => {
                 let peeled = self.peel_off_references(pat, expected, def_bm);
@@ -2056,61 +2065,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat_info: PatInfo<'tcx, '_>,
         consumed_inherited_ref: bool,
     ) -> Ty<'tcx> {
-        let tcx = self.tcx;
-        let expected = self.shallow_resolve(expected);
-        let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
-            Ok(()) => {
-                // `demand::subtype` would be good enough, but using `eqtype` turns
-                // out to be equally general. See (note_1) for details.
-
-                // Take region, inner-type from expected type if we can,
-                // to avoid creating needless variables. This also helps with
-                // the bad interactions of the given hack detailed in (note_1).
-                debug!("check_pat_ref: expected={:?}", expected);
-                match *expected.kind() {
-                    ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
-                    _ => {
-                        if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
-                            // We already matched against a match-ergonmics inserted reference,
-                            // so we don't need to match against a reference from the original type.
-                            // Save this infor for use in lowering later
-                            self.typeck_results
-                                .borrow_mut()
-                                .skipped_ref_pats_mut()
-                                .insert(pat.hir_id);
-                            (expected, expected)
-                        } else {
-                            let inner_ty = self.next_ty_var(TypeVariableOrigin {
-                                param_def_id: None,
-                                span: inner.span,
-                            });
-                            let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
-                            debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
-                            let err = self.demand_eqtype_pat_diag(
-                                pat.span,
-                                expected,
-                                ref_ty,
-                                pat_info.top_info,
-                            );
+        if consumed_inherited_ref
+            && pat.span.at_least_rust_2024()
+            && self.tcx.features().ref_pat_eat_one_layer_2024
+        {
+            self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
+            self.check_pat(inner, expected, pat_info);
+            expected
+        } else {
+            let tcx = self.tcx;
+            let expected = self.shallow_resolve(expected);
+            let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
+                Ok(()) => {
+                    // `demand::subtype` would be good enough, but using `eqtype` turns
+                    // out to be equally general. See (note_1) for details.
+
+                    // Take region, inner-type from expected type if we can,
+                    // to avoid creating needless variables. This also helps with
+                    // the bad interactions of the given hack detailed in (note_1).
+                    debug!("check_pat_ref: expected={:?}", expected);
+                    match *expected.kind() {
+                        ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
+                        _ => {
+                            if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
+                                // We already matched against a match-ergonmics inserted reference,
+                                // so we don't need to match against a reference from the original type.
+                                // Save this infor for use in lowering later
+                                self.typeck_results
+                                    .borrow_mut()
+                                    .skipped_ref_pats_mut()
+                                    .insert(pat.hir_id);
+                                (expected, expected)
+                            } else {
+                                let inner_ty = self.next_ty_var(TypeVariableOrigin {
+                                    param_def_id: None,
+                                    span: inner.span,
+                                });
+                                let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
+                                debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+                                let err = self.demand_eqtype_pat_diag(
+                                    pat.span,
+                                    expected,
+                                    ref_ty,
+                                    pat_info.top_info,
+                                );
 
-                            // Look for a case like `fn foo(&foo: u32)` and suggest
-                            // `fn foo(foo: &u32)`
-                            if let Some(mut err) = err {
-                                self.borrow_pat_suggestion(&mut err, pat);
-                                err.emit();
+                                // Look for a case like `fn foo(&foo: u32)` and suggest
+                                // `fn foo(foo: &u32)`
+                                if let Some(mut err) = err {
+                                    self.borrow_pat_suggestion(&mut err, pat);
+                                    err.emit();
+                                }
+                                (ref_ty, inner_ty)
                             }
-                            (ref_ty, inner_ty)
                         }
                     }
                 }
-            }
-            Err(guar) => {
-                let err = Ty::new_error(tcx, guar);
-                (err, err)
-            }
-        };
-        self.check_pat(inner, inner_ty, pat_info);
-        ref_ty
+                Err(guar) => {
+                    let err = Ty::new_error(tcx, guar);
+                    (err, err)
+                }
+            };
+            self.check_pat(inner, inner_ty, pat_info);
+            ref_ty
+        }
     }
 
     /// Create a reference type with a fresh region variable.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index bfd0f77c237..baf7fab3ad8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1460,6 +1460,7 @@ symbols! {
         receiver,
         recursion_limit,
         reexport_test_harness_main,
+        ref_pat_eat_one_layer_2024,
         ref_pat_everywhere,
         ref_unwind_safe_trait,
         reference,
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
new file mode 100644
index 00000000000..83f1ee6a77e
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
@@ -0,0 +1,37 @@
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+
+pub fn main() {
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(Some(&0)) {
+        let _: &u32 = x;
+        //~^ ERROR: mismatched types
+    }
+    if let Some(Some(&&x)) = &Some(Some(&0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
new file mode 100644
index 00000000000..132fe421a18
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
@@ -0,0 +1,128 @@
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22
+   |
+LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
+   |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(Some(x)) = &Some(&Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23
+   |
+LL |         let _: &u32 = x;
+   |                ----   ^ expected `&u32`, found integer
+   |                |
+   |                expected due to this
+   |
+help: consider borrowing here
+   |
+LL |         let _: &u32 = &x;
+   |                       +
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23
+   |
+LL |     if let Some(Some(&&x)) = &Some(Some(&0)) {
+   |                       ^^     --------------- this expression has type `&Option<Option<&{integer}>>`
+   |                       |
+   |                       expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     if let Some(Some(&&x)) = &Some(Some(&0)) {
+LL +     if let Some(Some(&x)) = &Some(Some(&0)) {
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&_`
+   |
+   = note:   expected enum `Option<{integer}>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22
+   |
+LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
+   |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(Some(x)) = &Some(&Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27
+   |
+LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+   |                           ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                           |
+   |                           expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
+   |                           ~
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
+   |
+LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
+   |
+LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+   |                       ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(&Some(x)) = &mut Some(&Some(0)) {
+   |                       ~
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs
new file mode 100644
index 00000000000..d28567f2859
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs
@@ -0,0 +1,37 @@
+//@ edition: 2021
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+pub fn main() {
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(Some(&0)) {
+        let _: &u32 = x;
+        //~^ ERROR: mismatched types
+    }
+    if let Some(Some(&&x)) = &Some(Some(&0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr
new file mode 100644
index 00000000000..28706f89c06
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr
@@ -0,0 +1,128 @@
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:5:22
+   |
+LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
+   |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(Some(x)) = &Some(&Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:10:23
+   |
+LL |         let _: &u32 = x;
+   |                ----   ^ expected `&u32`, found integer
+   |                |
+   |                expected due to this
+   |
+help: consider borrowing here
+   |
+LL |         let _: &u32 = &x;
+   |                       +
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:13:23
+   |
+LL |     if let Some(Some(&&x)) = &Some(Some(&0)) {
+   |                       ^^     --------------- this expression has type `&Option<Option<&{integer}>>`
+   |                       |
+   |                       expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     if let Some(Some(&&x)) = &Some(Some(&0)) {
+LL +     if let Some(Some(&x)) = &Some(Some(&0)) {
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:17:17
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&_`
+   |
+   = note:   expected enum `Option<{integer}>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:25:22
+   |
+LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
+   |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(Some(x)) = &Some(&Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:29:27
+   |
+LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+   |                           ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                           |
+   |                           expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
+   |                           ~
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
+   |
+LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
+   |
+LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+   |                       ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(&Some(x)) = &mut Some(&Some(0)) {
+   |                       ~
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
new file mode 100644
index 00000000000..f8378427383
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
@@ -0,0 +1,32 @@
+//@ run-pass
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+
+pub fn main() {
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(Some(&0)) {
+        let _: &u32 = x;
+    }
+    if let Some(Some(&&x)) = &Some(Some(&0)) {
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(&Some(&mut x)) = &mut Some(& Some(0)) {
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
new file mode 100644
index 00000000000..566196c1a32
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
@@ -0,0 +1,13 @@
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+
+pub fn main() {
+    if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&Some(&_)) = &Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr
new file mode 100644
index 00000000000..96a107b5c50
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17
+   |
+LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+   |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note:      expected reference `&Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23
+   |
+LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
+   |                       ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.