Skip to content

Commit 372847d

Browse files
Implement TC's match ergonomics 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 372847d

11 files changed

+451
-73
lines changed

Diff for: compiler/rustc_ast/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ pub enum ByRef {
711711
}
712712

713713
impl ByRef {
714+
#[must_use]
714715
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
715716
if let ByRef::Yes(old_mutbl) = &mut self {
716717
*old_mutbl = cmp::min(*old_mutbl, mutbl);

Diff for: compiler/rustc_feature/src/unstable.rs

+2
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.

Diff for: compiler/rustc_hir_typeck/src/pat.rs

+55-29
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
328328
adjust_mode: AdjustMode,
329329
max_ref_mutbl: MutblCap,
330330
) -> (Ty<'tcx>, ByRef, MutblCap) {
331-
if let ByRef::Yes(Mutability::Mut) = def_br {
332-
debug_assert!(max_ref_mutbl == MutblCap::Mut);
331+
#[cfg(debug_assertions)]
332+
if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
333+
span_bug!(pat.span, "Pattern mutability cap violated!");
333334
}
334335
match adjust_mode {
335336
AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
@@ -437,7 +438,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437438
});
438439
}
439440

440-
if self.tcx.features().ref_pat_eat_one_layer_2024 {
441+
let features = self.tcx.features();
442+
if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural {
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 features = tcx.features();
2132+
let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024;
2133+
let ref_pat_eat_one_layer_2024_structural = 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,49 @@ 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 {
21412153
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2142-
// ref pattern consumes inherited reference
2143-
2144-
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
2154+
if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() {
2155+
// Don't attempt to consume inherited reference
2156+
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
2157+
} else {
2158+
// ref pattern attempts to consume inherited reference
2159+
if pat_mutbl > inh_mut {
2160+
// Tried to match inherited `ref` with `&mut`
2161+
if !ref_pat_eat_one_layer_2024_structural {
2162+
let err_msg = "mismatched types";
2163+
let err = if let Some(span) = pat_prefix_span {
2164+
let mut err = self.dcx().struct_span_err(span, err_msg);
2165+
err.code(E0308);
2166+
err.note("cannot match inherited `&` with `&mut` pattern");
2167+
err.span_suggestion_verbose(
2168+
span,
2169+
"replace this `&mut` pattern with `&`",
2170+
"&",
2171+
Applicability::MachineApplicable,
2172+
);
2173+
err
2174+
} else {
2175+
self.dcx().struct_span_err(pat.span, err_msg)
2176+
};
2177+
err.emit();
2178+
2179+
pat_info.binding_mode = ByRef::No;
2180+
self.typeck_results
2181+
.borrow_mut()
2182+
.skipped_ref_pats_mut()
2183+
.insert(pat.hir_id);
2184+
self.check_pat(inner, expected, pat_info);
2185+
return expected;
2186+
}
21562187
} else {
2157-
self.dcx().struct_span_err(pat.span, err_msg)
2158-
};
2159-
err.emit();
2188+
pat_info.binding_mode = ByRef::No;
2189+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2190+
self.check_pat(inner, expected, pat_info);
2191+
return expected;
2192+
}
21602193
}
2161-
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;
21662194
}
21672195
} else {
21682196
// Reset binding mode on old editions
@@ -2177,8 +2205,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21772205
}
21782206
}
21792207

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

Diff for: compiler/rustc_span/src/symbol.rs

+1
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,

Diff for: tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs

+1
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)) {

Diff for: tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr

+10-10
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
| ^^^^^^

Diff for: tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs

+11-1
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)