Skip to content

Commit 0d1c47e

Browse files
Implement TC's match ergononics 2024 proposal
Under gate `ref_pat_eat_one_layer_2024_structural`. Enabling `ref_pat_eat_one_layer_2024` at the same time allows the union of what the individual gates allow.
1 parent 4bc39f0 commit 0d1c47e

10 files changed

+443
-71
lines changed

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ declare_features! (
573573
(unstable, raw_ref_op, "1.41.0", Some(64490)),
574574
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
575575
(incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
576+
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
577+
(incomplete, ref_pat_eat_one_layer_2024_structural, "1.79.0", Some(123076)),
576578
/// Allows using the `#[register_tool]` attribute.
577579
(unstable, register_tool, "1.41.0", Some(66079)),
578580
/// Allows the `#[repr(i128)]` attribute for enums.

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437437
});
438438
}
439439

440-
if self.tcx.features().ref_pat_eat_one_layer_2024 {
440+
if self.tcx.features().ref_pat_eat_one_layer_2024
441+
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural
442+
{
441443
def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
442444
if def_br == ByRef::Yes(Mutability::Not) {
443445
max_ref_mutbl = MutblCap::Not;
@@ -669,7 +671,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
669671
// Determine the binding mode...
670672
let bm = match user_bind_annot {
671673
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
672-
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
674+
if pat.span.at_least_rust_2024()
675+
&& (self.tcx.features().ref_pat_eat_one_layer_2024
676+
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural)
677+
{
673678
if !self.tcx.features().mut_ref {
674679
feature_err(
675680
&self.tcx.sess,
@@ -2122,7 +2127,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21222127
mut expected: Ty<'tcx>,
21232128
mut pat_info: PatInfo<'tcx, '_>,
21242129
) -> Ty<'tcx> {
2125-
let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024;
2130+
let tcx = self.tcx;
2131+
let ref_pat_eat_one_layer_2024 = tcx.features().ref_pat_eat_one_layer_2024;
2132+
let ref_pat_eat_one_layer_2024_structural =
2133+
tcx.features().ref_pat_eat_one_layer_2024_structural;
2134+
2135+
let no_ref_mut_behind_and =
2136+
ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural;
21262137
let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and;
21272138

21282139
let pat_prefix_span =
@@ -2137,32 +2148,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21372148
pat_info.max_ref_mutbl = MutblCap::Mut;
21382149
}
21392150

2151+
expected = self.try_structurally_resolve_type(pat.span, expected);
21402152
if new_match_ergonomics {
2141-
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2142-
// ref pattern consumes inherited reference
2153+
if let ByRef::Yes(inh_mut) = pat_info.binding_mode
2154+
&& (ref_pat_eat_one_layer_2024 || !expected.is_ref())
2155+
{
2156+
// ref pattern attempts to consume inherited reference
21432157

21442158
if pat_mutbl > inh_mut {
2145-
// Tried to match inherited `ref` with `&mut`, which is an error
2146-
let err_msg = "cannot match inherited `&` with `&mut` pattern";
2147-
let err = if let Some(span) = pat_prefix_span {
2148-
let mut err = self.dcx().struct_span_err(span, err_msg);
2149-
err.span_suggestion_verbose(
2150-
span,
2151-
"replace this `&mut` pattern with `&`",
2152-
"&",
2153-
Applicability::MachineApplicable,
2154-
);
2155-
err
2156-
} else {
2157-
self.dcx().struct_span_err(pat.span, err_msg)
2158-
};
2159-
err.emit();
2160-
}
2159+
// Tried to match inherited `ref` with `&mut`
2160+
if !ref_pat_eat_one_layer_2024_structural {
2161+
let err_msg = "mismatched types";
2162+
let err = if let Some(span) = pat_prefix_span {
2163+
let mut err = self.dcx().struct_span_err(span, err_msg);
2164+
err.code(E0308);
2165+
err.note("cannot match inherited `&` with `&mut` pattern");
2166+
err.span_suggestion_verbose(
2167+
span,
2168+
"replace this `&mut` pattern with `&`",
2169+
"&",
2170+
Applicability::MachineApplicable,
2171+
);
2172+
err
2173+
} else {
2174+
self.dcx().struct_span_err(pat.span, err_msg)
2175+
};
2176+
err.emit();
21612177

2162-
pat_info.binding_mode = ByRef::No;
2163-
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2164-
self.check_pat(inner, expected, pat_info);
2165-
return expected;
2178+
pat_info.binding_mode = ByRef::No;
2179+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2180+
self.check_pat(inner, expected, pat_info);
2181+
return expected;
2182+
}
2183+
} else {
2184+
pat_info.binding_mode = ByRef::No;
2185+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2186+
self.check_pat(inner, expected, pat_info);
2187+
return expected;
2188+
}
21662189
}
21672190
} else {
21682191
// Reset binding mode on old editions
@@ -2177,8 +2200,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21772200
}
21782201
}
21792202

2180-
let tcx = self.tcx;
2181-
expected = self.try_structurally_resolve_type(pat.span, expected);
21822203
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
21832204
Ok(()) => {
21842205
// `demand::subtype` would be good enough, but using `eqtype` turns

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,7 @@ symbols! {
15021502
recursion_limit,
15031503
reexport_test_harness_main,
15041504
ref_pat_eat_one_layer_2024,
1505+
ref_pat_eat_one_layer_2024_structural,
15051506
ref_pat_everywhere,
15061507
ref_unwind_safe_trait,
15071508
reference,

tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//@ edition: 2024
22
//@ compile-flags: -Zunstable-options
3+
// gate-test-ref_pat_eat_one_layer_2024_structural
34

45
pub fn main() {
56
if let Some(Some(&x)) = &Some(&Some(0)) {

tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22
2+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:6:22
33
|
44
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
55
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -14,7 +14,7 @@ LL | if let Some(Some(x)) = &Some(&Some(0)) {
1414
| ~
1515

1616
error[E0308]: mismatched types
17-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23
17+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:11:23
1818
|
1919
LL | let _: &u32 = x;
2020
| ---- ^ expected `&u32`, found integer
@@ -27,7 +27,7 @@ LL | let _: &u32 = &x;
2727
| +
2828

2929
error[E0308]: mismatched types
30-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23
30+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:14:23
3131
|
3232
LL | if let Some(Some(&&x)) = &Some(Some(&0)) {
3333
| ^^ --------------- this expression has type `&Option<Option<&{integer}>>`
@@ -43,7 +43,7 @@ LL + if let Some(Some(&x)) = &Some(Some(&0)) {
4343
|
4444

4545
error[E0308]: mismatched types
46-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17
46+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:18:17
4747
|
4848
LL | if let Some(&Some(x)) = &Some(Some(0)) {
4949
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
@@ -54,7 +54,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) {
5454
found reference `&_`
5555

5656
error[E0308]: mismatched types
57-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
57+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22
5858
|
5959
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
6060
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
@@ -64,7 +64,7 @@ LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
6464
= note: expected type `{integer}`
6565
found mutable reference `&mut _`
6666
note: to declare a mutable binding use: `mut x`
67-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
67+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22
6868
|
6969
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
7070
| ^^^^^^
@@ -74,7 +74,7 @@ LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
7474
| ~
7575

7676
error[E0308]: mismatched types
77-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22
77+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:26:22
7878
|
7979
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
8080
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -89,7 +89,7 @@ LL | if let Some(Some(x)) = &Some(&Some(0)) {
8989
| ~
9090

9191
error[E0308]: mismatched types
92-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27
92+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:30:27
9393
|
9494
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
9595
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
@@ -104,7 +104,7 @@ LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
104104
| ~
105105

106106
error[E0308]: mismatched types
107-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
107+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23
108108
|
109109
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
110110
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
@@ -114,7 +114,7 @@ LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
114114
= note: expected type `{integer}`
115115
found mutable reference `&mut _`
116116
note: to declare a mutable binding use: `mut x`
117-
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
117+
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23
118118
|
119119
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
120120
| ^^^^^^

tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//@ run-pass
22
//@ edition: 2024
33
//@ compile-flags: -Zunstable-options
4+
//@ revisions: classic structural both
45
#![allow(incomplete_features)]
5-
#![feature(ref_pat_eat_one_layer_2024)]
6+
#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
7+
#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
68

79
pub fn main() {
810
if let Some(Some(&x)) = &Some(&Some(0)) {
@@ -53,4 +55,12 @@ pub fn main() {
5355
if let Some(&Some(x)) = &mut Some(Some(0)) {
5456
let _: u32 = x;
5557
}
58+
#[cfg(any(classic, both))]
59+
if let Some(&mut x) = &mut Some(&0) {
60+
let _: &u32 = x;
61+
}
62+
#[cfg(any(structural, both))]
63+
if let Some(&mut x) = &Some(&mut 0) {
64+
let _: &u32 = x;
65+
}
5666
}

0 commit comments

Comments
 (0)