about summary refs log tree commit diff
diff options
context:
space:
mode:
authordianne <diannes.gm@gmail.com>2025-01-13 00:07:16 -0800
committerdianne <diannes.gm@gmail.com>2025-01-20 16:03:37 -0800
commit586ff158a25f421983be7b9f41437a73e56ef3cc (patch)
treebf292e8d86986abb2ba331ff6e96160183327550
parentf8315ae3b586fcd476e3dafd85b5891ddc70cc33 (diff)
downloadrust-586ff158a25f421983be7b9f41437a73e56ef3cc.tar.gz
rust-586ff158a25f421983be7b9f41437a73e56ef3cc.zip
"structural" ruleset: match against the inherited ref when a reference pattern doesn't match the mutability of an inner reference
This is the `Deref(EatInner, FallbackToOuter)` rule in Typing Rust Patterns.
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs13
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr22
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs5
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr71
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs25
5 files changed, 72 insertions, 64 deletions
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index ba5ba7a7452..992ab8cefc0 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -2327,8 +2327,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return expected;
                 }
                 InheritedRefMatchRule::EatInner => {
-                    if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
+                    if let ty::Ref(_, _, r_mutbl) = *expected.kind()
+                        && pat_mutbl <= r_mutbl
+                    {
                         // Match against the reference type; don't consume the inherited ref.
+                        // NB: The check for compatible pattern and ref type mutability assumes that
+                        // `&` patterns can match against mutable references (RFC 3627, Rule 5). If
+                        // we implement a pattern typing ruleset with Rule 4 (including the fallback
+                        // to matching the inherited ref when the inner ref can't match) but not
+                        // Rule 5, we'll need to check that here.
+                        debug_assert!(ref_pat_matches_mut_ref);
                         // NB: For RFC 3627's Rule 3, we limit the default binding mode's ref
                         // mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing
                         // ruleset with Rule 4 but not Rule 3, we'll need to check that here.
@@ -2336,7 +2344,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
                         pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
                     } else {
-                        // The expected type isn't a reference, so match against the inherited ref.
+                        // The reference pattern can't match against the expected type, so try
+                        // matching against the inherited ref instead.
                         if pat_mutbl > inh_mut {
                             // We can't match an inherited shared reference with `&mut`.
                             // NB: This assumes that `&` patterns can match against mutable
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr
index 6993e724be2..45ee489c520 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:15:17
+  --> $DIR/pattern-errors.rs:10:17
    |
 LL |     if let Some(&mut x) = &Some(&mut 0) {
    |                 ^^^^^
@@ -11,7 +11,7 @@ LL |     if let Some(&x) = &Some(&mut 0) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:19:17
+  --> $DIR/pattern-errors.rs:14:17
    |
 LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
    |                 ^^^^^
@@ -23,7 +23,7 @@ LL |     if let Some(&Some(&x)) = &Some(&mut Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:23:22
+  --> $DIR/pattern-errors.rs:18:22
    |
 LL |     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
    |                      ^^^^^
@@ -35,7 +35,7 @@ LL |     if let Some(Some(&x)) = &Some(Some(&mut 0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:28:17
+  --> $DIR/pattern-errors.rs:23:17
    |
 LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
    |                 ^^^^^
@@ -47,7 +47,7 @@ LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:34:23
+  --> $DIR/pattern-errors.rs:29:23
    |
 LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^
@@ -59,7 +59,7 @@ LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
    |                       ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:40:17
+  --> $DIR/pattern-errors.rs:35:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^
@@ -71,7 +71,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:43:17
+  --> $DIR/pattern-errors.rs:38:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^
@@ -83,7 +83,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:123:10
+  --> $DIR/pattern-errors.rs:118:10
    |
 LL |     let [&mut x] = &[&mut 0];
    |          ^^^^^
@@ -95,7 +95,7 @@ LL |     let [&x] = &[&mut 0];
    |          ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:128:10
+  --> $DIR/pattern-errors.rs:123:10
    |
 LL |     let [&mut &x] = &[&mut 0];
    |          ^^^^^
@@ -107,7 +107,7 @@ LL |     let [&&x] = &[&mut 0];
    |          ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:133:10
+  --> $DIR/pattern-errors.rs:128:10
    |
 LL |     let [&mut &ref x] = &[&mut 0];
    |          ^^^^^
@@ -119,7 +119,7 @@ LL |     let [&&ref x] = &[&mut 0];
    |          ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:138:10
+  --> $DIR/pattern-errors.rs:133:10
    |
 LL |     let [&mut &(mut x)] = &[&mut 0];
    |          ^^^^^
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
index bbaa717e8bd..1e170b7d3f8 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
@@ -7,11 +7,6 @@
 #![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
-    if let Some(&mut x) = &mut Some(&0) {
-        //[structural]~^ ERROR: mismatched types
-        let _: &u32 = x;
-    }
-
     if let Some(&mut x) = &Some(&mut 0) {
         //[classic]~^ ERROR: mismatched types
         let _: &u32 = x;
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
index d835a3abe37..3396d414819 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
@@ -1,36 +1,17 @@
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:10:17
+  --> $DIR/pattern-errors.rs:23:17
    |
-LL |     if let Some(&mut x) = &mut Some(&0) {
-   |                 ^^^^^^    ------------- this expression has type `&mut Option<&{integer}>`
-   |                 |
-   |                 types differ in mutability
-   |
-   = note:      expected reference `&{integer}`
-           found mutable reference `&mut _`
-note: to declare a mutable binding use: `mut x`
-  --> $DIR/pattern-errors.rs:10:17
+LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+   |                 ^^^^^
    |
-LL |     if let Some(&mut x) = &mut Some(&0) {
-   |                 ^^^^^^
-help: consider removing `&mut` from the pattern
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
    |
-LL |     if let Some(x) = &mut Some(&0) {
+LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:28: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/pattern-errors.rs:31:23
+  --> $DIR/pattern-errors.rs:26:23
    |
 LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
    |                       ^^^^^
@@ -42,7 +23,7 @@ LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
    |                       ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:34:23
+  --> $DIR/pattern-errors.rs:29:23
    |
 LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^
@@ -54,7 +35,7 @@ LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
    |                       ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:37:29
+  --> $DIR/pattern-errors.rs:32:29
    |
 LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
    |                             ^^^^^
@@ -66,7 +47,7 @@ LL |     if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) {
    |                             ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:40:17
+  --> $DIR/pattern-errors.rs:35:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^
@@ -78,7 +59,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:43:17
+  --> $DIR/pattern-errors.rs:38:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^
@@ -90,7 +71,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:49:11
+  --> $DIR/pattern-errors.rs:44:11
    |
 LL |     let &[&mut x] = &&mut [0];
    |           ^^^^^
@@ -102,7 +83,7 @@ LL |     let &[&x] = &&mut [0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:54:11
+  --> $DIR/pattern-errors.rs:49:11
    |
 LL |     let &[&mut x] = &mut &mut [0];
    |           ^^^^^
@@ -114,7 +95,7 @@ LL |     let &[&x] = &mut &mut [0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:59:11
+  --> $DIR/pattern-errors.rs:54:11
    |
 LL |     let &[&mut ref x] = &&mut [0];
    |           ^^^^^
@@ -126,7 +107,7 @@ LL |     let &[&ref x] = &&mut [0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:64:11
+  --> $DIR/pattern-errors.rs:59:11
    |
 LL |     let &[&mut ref x] = &mut &mut [0];
    |           ^^^^^
@@ -138,7 +119,7 @@ LL |     let &[&ref x] = &mut &mut [0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:69:11
+  --> $DIR/pattern-errors.rs:64:11
    |
 LL |     let &[&mut mut x] = &&mut [0];
    |           ^^^^^
@@ -150,7 +131,7 @@ LL |     let &[&mut x] = &&mut [0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:74:11
+  --> $DIR/pattern-errors.rs:69:11
    |
 LL |     let &[&mut mut x] = &mut &mut [0];
    |           ^^^^^
@@ -162,7 +143,7 @@ LL |     let &[&mut x] = &mut &mut [0];
    |           ~
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/pattern-errors.rs:81:12
+  --> $DIR/pattern-errors.rs:76:12
    |
 LL |     let [&(mut x)] = &[&0];
    |            ^^^^
@@ -172,7 +153,7 @@ LL |     let [&(mut x)] = &[&0];
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/pattern-errors.rs:85:12
+  --> $DIR/pattern-errors.rs:80:12
    |
 LL |     let [&(mut x)] = &mut [&0];
    |            ^^^^
@@ -182,7 +163,7 @@ LL |     let [&(mut x)] = &mut [&0];
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:91:11
+  --> $DIR/pattern-errors.rs:86:11
    |
 LL |     let [&&mut x] = &[&mut 0];
    |           ^^^^^
@@ -194,7 +175,7 @@ LL |     let [&&x] = &[&mut 0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:96:11
+  --> $DIR/pattern-errors.rs:91:11
    |
 LL |     let [&&mut x] = &mut [&mut 0];
    |           ^^^^^
@@ -206,7 +187,7 @@ LL |     let [&&x] = &mut [&mut 0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:101:11
+  --> $DIR/pattern-errors.rs:96:11
    |
 LL |     let [&&mut ref x] = &[&mut 0];
    |           ^^^^^
@@ -218,7 +199,7 @@ LL |     let [&&ref x] = &[&mut 0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:106:11
+  --> $DIR/pattern-errors.rs:101:11
    |
 LL |     let [&&mut ref x] = &mut [&mut 0];
    |           ^^^^^
@@ -230,7 +211,7 @@ LL |     let [&&ref x] = &mut [&mut 0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:111:11
+  --> $DIR/pattern-errors.rs:106:11
    |
 LL |     let [&&mut mut x] = &[&mut 0];
    |           ^^^^^
@@ -242,7 +223,7 @@ LL |     let [&&mut x] = &[&mut 0];
    |           ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:116:11
+  --> $DIR/pattern-errors.rs:111:11
    |
 LL |     let [&&mut mut x] = &mut [&mut 0];
    |           ^^^^^
@@ -253,7 +234,7 @@ help: replace this `&mut` pattern with `&`
 LL |     let [&&mut x] = &mut [&mut 0];
    |           ~
 
-error: aborting due to 21 previous errors
+error: aborting due to 20 previous errors
 
 Some errors have detailed explanations: E0308, E0658.
 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 28e008a779b..1db7abc473e 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
@@ -3,7 +3,7 @@
 //@ run-pass
 //! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we
 //! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests.
-#![allow(incomplete_features)]
+#![allow(incomplete_features, unused_mut)]
 #![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
 #![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
@@ -53,4 +53,27 @@ pub fn main() {
     if let Some(&Some(x)) = &mut Some(Some(0)) {
         let _: u32 = x;
     }
+
+    // Tests for eat-inner rulesets matching on the outer reference if matching on the inner
+    // reference causes a mutability mismatch, i.e. `Deref(EatInner, FallbackToOuter)`:
+    let [&mut x] = &mut [&0];
+    let _: &u32 = x;
+
+    let [&mut ref x] = &mut [&0];
+    let _: &&u32 = x;
+
+    let [&mut ref mut x] = &mut [&0];
+    let _: &mut &u32 = x;
+
+    let [&mut mut x] = &mut [&0];
+    let _: &u32 = x;
+
+    let [&mut &x] = &mut [&0];
+    let _: u32 = x;
+
+    let [&mut &ref x] = &mut [&0];
+    let _: &u32 = x;
+
+    let [&mut &(mut x)] = &mut [&0];
+    let _: u32 = x;
 }