From 586ff158a25f421983be7b9f41437a73e56ef3cc Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 13 Jan 2025 00:07:16 -0800 Subject: [PATCH] "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. --- compiler/rustc_hir_typeck/src/pat.rs | 13 +++- .../pattern-errors.classic.stderr | 22 +++--- .../experimental/pattern-errors.rs | 5 -- .../pattern-errors.structural.stderr | 71 +++++++------------ .../experimental/well-typed-edition-2024.rs | 25 ++++++- 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 +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^ | - = note: expected reference `&{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/pattern-errors.rs:10:17 + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` | -LL | if let Some(&mut x) = &mut Some(&0) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -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; }