Skip to content

Commit

Permalink
Rollup merge of #131381 - Nadrieril:min-match-ergonomics, r=pnkfelix
Browse files Browse the repository at this point in the history
Implement edition 2024 match ergonomics restrictions

This implements the minimalest version of [match ergonomics for edition 2024](https://rust-lang.github.io/rfcs/3627-match-ergonomics-2024.html). This minimal version makes it an error to ever reset the default binding mode. The implemented proposal is described precisely [here](https://hackmd.io/zUqs2ISNQ0Wrnxsa9nhD0Q#RFC-3627-nano), where it is called "RFC 3627-nano".

Rules:
- Rule 1C: When the DBM (default binding mode) is not `move` (whether or not behind a reference), writing `mut`, `ref`, or `ref mut` on a binding is an error.
- Rule 2C: Reference patterns can only match against references in the scrutinee when the DBM is `move`.

This minimal version is forward-compatible with the main proposals for match ergonomics 2024: [RFC3627](https://rust-lang.github.io/rfcs/3627-match-ergonomics-2024.html) itself, the alternative [rule 4-early variant](https://rust-lang.github.io/rfcs/3627-match-ergonomics-2024.html), and [others](https://hackmd.io/zUqs2ISNQ0Wrnxsa9nhD0Q). The idea is to give us more time to iron out a final proposal.

This includes a migration lint that desugars any offending pattern into one that doesn't make use of match ergonomics. Such patterns have identical meaning across editions.

This PR insta-stabilizes the proposed behavior onto edition 2024.

r? `@ghost`

Tracking:

- #123076
  • Loading branch information
matthiaskrgr authored Oct 16, 2024
2 parents 1817de6 + 2ef0a8f commit c1ed1f1
Show file tree
Hide file tree
Showing 17 changed files with 757 additions and 242 deletions.
30 changes: 22 additions & 8 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,16 +690,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

BindingMode(def_br, Mutability::Mut)
} else {
// `mut` resets binding mode on edition <= 2021
self.typeck_results
// `mut` resets the binding mode on edition <= 2021
*self
.typeck_results
.borrow_mut()
.rust_2024_migration_desugared_pats_mut()
.insert(pat_info.top_info.hir_id);
.entry(pat_info.top_info.hir_id)
.or_default() |= pat.span.at_least_rust_2024();
BindingMode(ByRef::No, Mutability::Mut)
}
}
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
BindingMode(ByRef::Yes(_), _) => user_bind_annot,
BindingMode(ByRef::Yes(_), _) => {
if matches!(def_br, ByRef::Yes(_)) {
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
*self
.typeck_results
.borrow_mut()
.rust_2024_migration_desugared_pats_mut()
.entry(pat_info.top_info.hir_id)
.or_default() |= pat.span.at_least_rust_2024();
}
user_bind_annot
}
};

if bm.0 == ByRef::Yes(Mutability::Mut)
Expand Down Expand Up @@ -2204,14 +2217,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
} else {
// Reset binding mode on old editions

if pat_info.binding_mode != ByRef::No {
pat_info.binding_mode = ByRef::No;

self.typeck_results
*self
.typeck_results
.borrow_mut()
.rust_2024_migration_desugared_pats_mut()
.insert(pat_info.top_info.hir_id);
.entry(pat_info.top_info.hir_id)
.or_default() |= pat.span.at_least_rust_2024();
}
}

Expand Down Expand Up @@ -2262,6 +2275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(err, err)
}
};

self.check_pat(inner, inner_ty, pat_info);
ref_ty
}
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {

#[instrument(skip(self), level = "debug")]
fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
if self
if let Some(is_hard_error) = self
.fcx
.typeck_results
.borrow_mut()
Expand All @@ -645,7 +645,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
debug!(
"node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint"
);
self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id);
self.typeck_results
.rust_2024_migration_desugared_pats_mut()
.insert(hir_id, is_hard_error);
}
}

Expand Down
7 changes: 2 additions & 5 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1651,7 +1651,6 @@ declare_lint! {
/// ### Example
///
/// ```rust,edition2021
/// #![feature(ref_pat_eat_one_layer_2024)]
/// #![warn(rust_2024_incompatible_pat)]
///
/// if let Some(&a) = &Some(&0u8) {
Expand All @@ -1672,12 +1671,10 @@ declare_lint! {
pub RUST_2024_INCOMPATIBLE_PAT,
Allow,
"detects patterns whose meaning will change in Rust 2024",
@feature_gate = ref_pat_eat_one_layer_2024;
// FIXME uncomment below upon stabilization
/*@future_incompatible = FutureIncompatibleInfo {
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
reference: "123076",
};*/
};
}

declare_lint! {
Expand Down
15 changes: 8 additions & 7 deletions compiler/rustc_middle/src/ty/typeck_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ pub struct TypeckResults<'tcx> {
/// Stores the actual binding mode for all instances of [`BindingMode`].
pat_binding_modes: ItemLocalMap<BindingMode>,

/// Top-level patterns whose match ergonomics need to be desugared
/// by the Rust 2021 -> 2024 migration lint.
rust_2024_migration_desugared_pats: ItemLocalSet,
/// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024
/// migration lint. The boolean indicates whether the emitted diagnostic should be a hard error
/// (if any of the incompatible pattern elements are in edition 2024).
rust_2024_migration_desugared_pats: ItemLocalMap<bool>,

/// Stores the types which were implicitly dereferenced in pattern binding modes
/// for later usage in THIR lowering. For example,
Expand Down Expand Up @@ -418,15 +419,15 @@ impl<'tcx> TypeckResults<'tcx> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
}

pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> {
LocalSetInContext {
pub fn rust_2024_migration_desugared_pats(&self) -> LocalTableInContext<'_, bool> {
LocalTableInContext {
hir_owner: self.hir_owner,
data: &self.rust_2024_migration_desugared_pats,
}
}

pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
LocalSetInContextMut {
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalTableInContextMut<'_, bool> {
LocalTableInContextMut {
hir_owner: self.hir_owner,
data: &mut self.rust_2024_migration_desugared_pats,
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
mir_build_rust_2024_incompatible_pat = the semantics of this pattern will change in edition 2024
mir_build_rust_2024_incompatible_pat = patterns are not allowed to reset the default binding mode in edition 2024
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
.attributes = no other attributes may be applied
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,8 @@ pub(crate) struct Rust2024IncompatiblePat {

pub(crate) struct Rust2024IncompatiblePatSugg {
pub(crate) suggestion: Vec<(Span, String)>,
/// Whether the incompatibility is a hard error because a relevant span is in edition 2024.
pub(crate) is_hard_error: bool,
}

impl Subdiagnostic for Rust2024IncompatiblePatSugg {
Expand Down
27 changes: 19 additions & 8 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use tracing::{debug, instrument};

pub(crate) use self::check_match::check_match;
use crate::errors::*;
use crate::fluent_generated as fluent;
use crate::thir::util::UserAnnotatedTyHelpers;

struct PatCtxt<'a, 'tcx> {
Expand All @@ -48,18 +49,28 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
typeck_results,
rust_2024_migration_suggestion: typeck_results
.rust_2024_migration_desugared_pats()
.contains(pat.hir_id)
.then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }),
.get(pat.hir_id)
.map(|&is_hard_error| Rust2024IncompatiblePatSugg {
suggestion: Vec::new(),
is_hard_error,
}),
};
let result = pcx.lower_pattern(pat);
debug!("pat_from_hir({:?}) = {:?}", pat, result);
if let Some(sugg) = pcx.rust_2024_migration_suggestion {
tcx.emit_node_span_lint(
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
pat.hir_id,
pat.span,
Rust2024IncompatiblePat { sugg },
);
if sugg.is_hard_error {
let mut err =
tcx.dcx().struct_span_err(pat.span, fluent::mir_build_rust_2024_incompatible_pat);
err.subdiagnostic(sugg);
err.emit();
} else {
tcx.emit_node_span_lint(
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
pat.hir_id,
pat.span,
Rust2024IncompatiblePat { sugg },
);
}
}
result
}
Expand Down
57 changes: 0 additions & 57 deletions tests/ui/pattern/match_ergonomics_2024.fixed

This file was deleted.

57 changes: 0 additions & 57 deletions tests/ui/pattern/match_ergonomics_2024.rs

This file was deleted.

Loading

0 comments on commit c1ed1f1

Please sign in to comment.