Skip to content

Commit 996ae06

Browse files
authored
Unrolled build for rust-lang#125168
Rollup merge of rust-lang#125168 - Jules-Bertholet:match-ergonomics-2024-align-with-rfc, r=Nadrieril Match ergonomics 2024: align implementation with RFC - Remove eat-two-layers (`ref_pat_everywhere`) - Consolidate `mut_preserve_binding_mode_2024` into `ref_pat_eat_one_layer_2024` - `&mut` no longer peels off `&` - Apply "no `ref mut` behind `&`" rule on all editions with `ref_pat_eat_one_layer_2024` - Require `mut_ref` feature gate for all mutable by-reference bindings r? ``@Nadrieril`` cc rust-lang#123076 ``@rustbot`` label A-edition-2024 A-patterns
2 parents 003a902 + af75014 commit 996ae06

18 files changed

+233
-343
lines changed

compiler/rustc_feature/src/removed.rs

+3
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ declare_features! (
128128
/// Allows the use of type alias impl trait in function return positions
129129
(removed, min_type_alias_impl_trait, "1.56.0", Some(63063),
130130
Some("removed in favor of full type_alias_impl_trait")),
131+
/// Make `mut` not reset the binding mode on edition >= 2024.
132+
(removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")),
131133
(removed, needs_allocator, "1.4.0", Some(27389),
132134
Some("subsumed by `#![feature(allocator_internals)]`")),
133135
/// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
@@ -181,6 +183,7 @@ declare_features! (
181183
(removed, pushpop_unsafe, "1.2.0", None, None),
182184
(removed, quad_precision_float, "1.0.0", None, None),
183185
(removed, quote, "1.33.0", Some(29601), None),
186+
(removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")),
184187
(removed, reflect, "1.0.0", Some(27749), None),
185188
/// Allows using the `#[register_attr]` attribute.
186189
(removed, register_attr, "1.65.0", Some(66080),

compiler/rustc_feature/src/unstable.rs

-4
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,6 @@ declare_features! (
529529
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
530530
/// Allows the `#[must_not_suspend]` attribute.
531531
(unstable, must_not_suspend, "1.57.0", Some(83310)),
532-
/// Make `mut` not reset the binding mode on edition >= 2024.
533-
(incomplete, mut_preserve_binding_mode_2024, "1.79.0", Some(123076)),
534532
/// Allows `mut ref` and `mut ref mut` identifier patterns.
535533
(incomplete, mut_ref, "1.79.0", Some(123076)),
536534
/// Allows using `#[naked]` on functions.
@@ -573,8 +571,6 @@ declare_features! (
573571
(unstable, raw_ref_op, "1.41.0", Some(64490)),
574572
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
575573
(incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
576-
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
577-
(incomplete, ref_pat_everywhere, "1.79.0", Some(123076)),
578574
/// Allows using the `#[register_tool]` attribute.
579575
(unstable, register_tool, "1.41.0", Some(66079)),
580576
/// Allows the `#[repr(i128)]` attribute for enums.

compiler/rustc_hir_typeck/src/pat.rs

+66-90
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_infer::infer;
1212
use rustc_middle::mir::interpret::ErrorHandled;
1313
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
1414
use rustc_middle::{bug, span_bug};
15-
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
15+
use rustc_session::{lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, parse::feature_err};
1616
use rustc_span::edit_distance::find_best_match_for_name;
1717
use rustc_span::hygiene::DesugaringKind;
1818
use rustc_span::source_map::Spanned;
@@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
335335
match adjust_mode {
336336
AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
337337
AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut),
338-
AdjustMode::Peel => {
339-
self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl)
340-
}
338+
AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl),
341339
}
342340
}
343341

@@ -408,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408406
pat: &'tcx Pat<'tcx>,
409407
expected: Ty<'tcx>,
410408
mut def_br: ByRef,
411-
max_peelable_mutability: Mutability,
412-
mut max_ref_mutability: MutblCap,
409+
mut max_ref_mutbl: MutblCap,
413410
) -> (Ty<'tcx>, ByRef, MutblCap) {
414411
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
415412
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
@@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
421418
//
422419
// See the examples in `ui/match-defbm*.rs`.
423420
let mut pat_adjustments = vec![];
424-
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
425-
&& inner_mutability <= max_peelable_mutability
426-
{
421+
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
427422
debug!("inspecting {:?}", expected);
428423

429424
debug!("current discriminant is Ref, inserting implicit deref");
@@ -443,10 +438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
443438
});
444439
}
445440

446-
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
447-
def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl());
441+
if self.tcx.features().ref_pat_eat_one_layer_2024 {
442+
def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
448443
if def_br == ByRef::Yes(Mutability::Not) {
449-
max_ref_mutability = MutblCap::Not;
444+
max_ref_mutbl = MutblCap::Not;
450445
}
451446
}
452447

@@ -458,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458453
.insert(pat.hir_id, pat_adjustments);
459454
}
460455

461-
(expected, def_br, max_ref_mutability)
456+
(expected, def_br, max_ref_mutbl)
462457
}
463458

464459
fn check_pat_lit(
@@ -674,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
674669

675670
// Determine the binding mode...
676671
let bm = match user_bind_annot {
677-
// `mut` resets binding mode on edition <= 2021
678-
BindingMode(ByRef::No, Mutability::Mut)
679-
if !(pat.span.at_least_rust_2024()
680-
&& self.tcx.features().mut_preserve_binding_mode_2024)
681-
&& matches!(def_br, ByRef::Yes(_)) =>
682-
{
683-
self.typeck_results
684-
.borrow_mut()
685-
.rust_2024_migration_desugared_pats_mut()
686-
.insert(pat_info.top_info.hir_id);
687-
BindingMode(ByRef::No, Mutability::Mut)
672+
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
673+
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
674+
if !self.tcx.features().mut_ref {
675+
feature_err(
676+
&self.tcx.sess,
677+
sym::mut_ref,
678+
pat.span.until(ident.span),
679+
"binding cannot be both mutable and by-reference",
680+
)
681+
.emit();
682+
}
683+
684+
BindingMode(def_br, Mutability::Mut)
685+
} else {
686+
// `mut` resets binding mode on edition <= 2021
687+
self.typeck_results
688+
.borrow_mut()
689+
.rust_2024_migration_desugared_pats_mut()
690+
.insert(pat_info.top_info.hir_id);
691+
BindingMode(ByRef::No, Mutability::Mut)
692+
}
688693
}
689694
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
690695
BindingMode(ByRef::Yes(_), _) => user_bind_annot,
@@ -2126,57 +2131,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21262131
mut expected: Ty<'tcx>,
21272132
mut pat_info: PatInfo<'tcx, '_>,
21282133
) -> Ty<'tcx> {
2129-
// FIXME: repace with `bool` once final decision on 1 vs 2 layers is made
2130-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2131-
enum MatchErgonomicsMode {
2132-
EatOneLayer,
2133-
EatTwoLayers,
2134-
Legacy,
2135-
}
2134+
let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024;
2135+
let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and;
21362136

2137-
let match_ergonomics_mode =
2138-
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
2139-
MatchErgonomicsMode::EatOneLayer
2140-
} else if self.tcx.features().ref_pat_everywhere {
2141-
MatchErgonomicsMode::EatTwoLayers
2142-
} else {
2143-
MatchErgonomicsMode::Legacy
2144-
};
2137+
let pat_prefix_span =
2138+
inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
21452139

2146-
let mut inherited_ref_mutbl_match = false;
2147-
if match_ergonomics_mode != MatchErgonomicsMode::Legacy {
2140+
if no_ref_mut_behind_and {
21482141
if pat_mutbl == Mutability::Not {
21492142
// Prevent the inner pattern from binding with `ref mut`.
2150-
pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(
2151-
inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)),
2152-
);
2143+
pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
21532144
}
2145+
} else {
2146+
pat_info.max_ref_mutbl = MutblCap::Mut;
2147+
}
21542148

2149+
if new_match_ergonomics {
21552150
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2156-
inherited_ref_mutbl_match = pat_mutbl <= inh_mut;
2157-
}
2151+
// ref pattern consumes inherited reference
2152+
2153+
if pat_mutbl > inh_mut {
2154+
// Tried to match inherited `ref` with `&mut`, which is an error
2155+
let err_msg = "cannot match inherited `&` with `&mut` pattern";
2156+
let err = if let Some(span) = pat_prefix_span {
2157+
let mut err = self.dcx().struct_span_err(span, err_msg);
2158+
err.span_suggestion_verbose(
2159+
span,
2160+
"replace this `&mut` pattern with `&`",
2161+
"&",
2162+
Applicability::MachineApplicable,
2163+
);
2164+
err
2165+
} else {
2166+
self.dcx().struct_span_err(pat.span, err_msg)
2167+
};
2168+
err.emit();
2169+
}
21582170

2159-
if inherited_ref_mutbl_match {
21602171
pat_info.binding_mode = ByRef::No;
2161-
if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer {
2162-
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2163-
self.check_pat(inner, expected, pat_info);
2164-
return expected;
2165-
}
2166-
} else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer
2167-
&& pat_mutbl == Mutability::Mut
2168-
{
2169-
// `&mut` patterns pell off `&` references
2170-
let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references(
2171-
pat,
2172-
expected,
2173-
pat_info.binding_mode,
2174-
Mutability::Not,
2175-
pat_info.max_ref_mutbl,
2176-
);
2177-
expected = new_expected;
2178-
pat_info.binding_mode = new_bm;
2179-
pat_info.max_ref_mutbl = max_ref_mutbl;
2172+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2173+
self.check_pat(inner, expected, pat_info);
2174+
return expected;
21802175
}
21812176
} else {
21822177
// Reset binding mode on old editions
@@ -2189,8 +2184,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21892184
.rust_2024_migration_desugared_pats_mut()
21902185
.insert(pat_info.top_info.hir_id);
21912186
}
2192-
2193-
pat_info.max_ref_mutbl = MutblCap::Mut;
21942187
}
21952188

21962189
let tcx = self.tcx;
@@ -2205,34 +2198,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22052198
// the bad interactions of the given hack detailed in (note_1).
22062199
debug!("check_pat_ref: expected={:?}", expected);
22072200
match *expected.kind() {
2208-
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => {
2209-
if r_mutbl == Mutability::Not
2210-
&& match_ergonomics_mode != MatchErgonomicsMode::Legacy
2211-
{
2201+
ty::Ref(_, r_ty, r_mutbl)
2202+
if (new_match_ergonomics && r_mutbl >= pat_mutbl)
2203+
|| r_mutbl == pat_mutbl =>
2204+
{
2205+
if no_ref_mut_behind_and && r_mutbl == Mutability::Not {
22122206
pat_info.max_ref_mutbl = MutblCap::Not;
22132207
}
22142208

22152209
(expected, r_ty)
22162210
}
22172211

2218-
// `&` pattern eats `&mut` reference
2219-
ty::Ref(_, r_ty, Mutability::Mut)
2220-
if pat_mutbl == Mutability::Not
2221-
&& match_ergonomics_mode != MatchErgonomicsMode::Legacy =>
2222-
{
2223-
(expected, r_ty)
2224-
}
2225-
2226-
_ if inherited_ref_mutbl_match
2227-
&& match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers =>
2228-
{
2229-
// We already matched against a match-ergonmics inserted reference,
2230-
// so we don't need to match against a reference from the original type.
2231-
// Save this info for use in lowering later
2232-
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2233-
(expected, expected)
2234-
}
2235-
22362212
_ => {
22372213
let inner_ty = self.next_ty_var(inner.span);
22382214
let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);

tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs

-14
This file was deleted.

tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr

-49
This file was deleted.

tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs

-15
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ pub fn main() {
2323
if let Some(Some(&x)) = &Some(&Some(0)) {
2424
let _: u32 = x;
2525
}
26-
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
27-
let _: u32 = x;
28-
}
2926
if let Some(&Some(&x)) = &mut Some(&Some(0)) {
3027
let _: u32 = x;
3128
}
@@ -35,9 +32,6 @@ pub fn main() {
3532
if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) {
3633
let _: &u32 = x;
3734
}
38-
if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
39-
let _: &u32 = x;
40-
}
4135
if let &Some(Some(x)) = &Some(&mut Some(0)) {
4236
let _: &u32 = x;
4337
}
@@ -59,13 +53,4 @@ pub fn main() {
5953
if let Some(&Some(x)) = &mut Some(Some(0)) {
6054
let _: u32 = x;
6155
}
62-
63-
let &mut x = &&mut 0;
64-
let _: &u32 = x;
65-
66-
let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
67-
let _: &u32 = x;
68-
69-
let &mut &mut &mut &mut x = &mut &&&&mut &&&mut &mut 0;
70-
let _: &u32 = x;
7156
}

0 commit comments

Comments
 (0)