Skip to content

Commit 84c3aa1

Browse files
committed
produce suggestions which remove reference patterns
This doesn't yet respect whether patterns are from macro expansions, so it may try to suggest changes within an expansion (leading to a test failure).
1 parent cc37b16 commit 84c3aa1

File tree

9 files changed

+271
-119
lines changed

9 files changed

+271
-119
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+3-20
Original file line numberDiff line numberDiff line change
@@ -2798,36 +2798,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27982798
// FIXME(ref_pat_eat_one_layer_2024): The migration diagnostic doesn't know how to track the
27992799
// default binding mode in the presence of Rule 3 or Rule 5. As a consequence, the labels it
28002800
// gives for default binding modes are wrong, as well as suggestions based on the default
2801-
// binding mode. This keeps it from making those suggestions, as doing so could panic.
2802-
let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
2803-
primary_labels: Vec::new(),
2804-
bad_modifiers: false,
2805-
bad_ref_pats: false,
2806-
suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
2807-
&& !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
2808-
});
2801+
// binding mode.
2802+
let info = table.entry(pat_id).or_default();
28092803

2810-
let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
2804+
let pat_kind = if matches!(subpat.kind, PatKind::Binding(..)) {
28112805
info.bad_modifiers = true;
2812-
// If the user-provided binding modifier doesn't match the default binding mode, we'll
2813-
// need to suggest reference patterns, which can affect other bindings.
2814-
// For simplicity, we opt to suggest making the pattern fully explicit.
2815-
info.suggest_eliding_modes &=
2816-
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
28172806
"binding modifier"
28182807
} else {
28192808
info.bad_ref_pats = true;
2820-
// For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
2821-
// suggest adding them instead, which can affect the types assigned to bindings.
2822-
// As such, we opt to suggest making the pattern fully explicit.
2823-
info.suggest_eliding_modes = false;
28242809
"reference pattern"
28252810
};
28262811
// Only provide a detailed label if the problematic subpattern isn't from an expansion.
28272812
// In the case that it's from a macro, we'll add a more detailed note in the emitter.
28282813
let primary_label = if from_expansion {
2829-
// We can't suggest eliding modifiers within expansions.
2830-
info.suggest_eliding_modes = false;
28312814
// NB: This wording assumes the only expansions that can produce problematic reference
28322815
// patterns and bindings are macros. If a desugaring or AST pass is added that can do
28332816
// so, we may want to inspect the span's source callee or macro backtrace.

compiler/rustc_middle/src/ty/typeck_results.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -812,14 +812,12 @@ impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> {
812812

813813
/// Information on a pattern incompatible with Rust 2024, for use by the error/migration diagnostic
814814
/// emitted during THIR construction.
815-
#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
815+
#[derive(TyEncodable, TyDecodable, Debug, Default, HashStable)]
816816
pub struct Rust2024IncompatiblePatInfo {
817817
/// Labeled spans for `&`s, `&mut`s, and binding modifiers incompatible with Rust 2024.
818818
pub primary_labels: Vec<(Span, String)>,
819819
/// Whether any binding modifiers occur under a non-`move` default binding mode.
820820
pub bad_modifiers: bool,
821821
/// Whether any `&` or `&mut` patterns occur under a non-`move` default binding mode.
822822
pub bad_ref_pats: bool,
823-
/// If `true`, we can give a simpler suggestion solely by eliding explicit binding modifiers.
824-
pub suggest_eliding_modes: bool,
825823
}

compiler/rustc_mir_build/src/errors.rs

+34-11
Original file line numberDiff line numberDiff line change
@@ -1106,22 +1106,29 @@ pub(crate) struct Rust2024IncompatiblePat<'m> {
11061106
}
11071107

11081108
pub(crate) struct Rust2024IncompatiblePatSugg<'m> {
1109-
/// If true, our suggestion is to elide explicit binding modifiers.
1110-
/// If false, our suggestion is to make the pattern fully explicit.
1111-
pub(crate) suggest_eliding_modes: bool,
11121109
pub(crate) suggestion: Vec<(Span, String)>,
1110+
/// If `Some(..)`, we provide a suggestion about either adding or removing syntax.
1111+
/// If `None`, we suggest both additions and removals; use a generic wording for simplicity.
1112+
pub(crate) kind: Option<Rust2024IncompatiblePatSuggKind>,
11131113
pub(crate) ref_pattern_count: usize,
11141114
pub(crate) binding_mode_count: usize,
11151115
/// Labels for where incompatibility-causing by-ref default binding modes were introduced.
11161116
pub(crate) default_mode_labels: &'m FxIndexMap<Span, ty::Mutability>,
11171117
}
11181118

1119+
pub(crate) enum Rust2024IncompatiblePatSuggKind {
1120+
Subtractive,
1121+
Additive,
1122+
}
1123+
11191124
impl<'m> Subdiagnostic for Rust2024IncompatiblePatSugg<'m> {
11201125
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
11211126
self,
11221127
diag: &mut Diag<'_, G>,
11231128
_f: &F,
11241129
) {
1130+
use Rust2024IncompatiblePatSuggKind::*;
1131+
11251132
// Format and emit explanatory notes about default binding modes. Reversing the spans' order
11261133
// means if we have nested spans, the innermost ones will be visited first.
11271134
for (&span, &def_br_mutbl) in self.default_mode_labels.iter().rev() {
@@ -1143,17 +1150,33 @@ impl<'m> Subdiagnostic for Rust2024IncompatiblePatSugg<'m> {
11431150
} else {
11441151
Applicability::MaybeIncorrect
11451152
};
1146-
let msg = if self.suggest_eliding_modes {
1147-
let plural_modes = pluralize!(self.binding_mode_count);
1148-
format!("remove the unnecessary binding modifier{plural_modes}")
1149-
} else {
1150-
let plural_derefs = pluralize!(self.ref_pattern_count);
1151-
let and_modes = if self.binding_mode_count > 0 {
1152-
format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
1153+
let msg = if let Some(kind) = self.kind {
1154+
let derefs = if self.ref_pattern_count > 0 {
1155+
format!("reference pattern{}", pluralize!(self.ref_pattern_count))
11531156
} else {
11541157
String::new()
11551158
};
1156-
format!("make the implied reference pattern{plural_derefs}{and_modes} explicit")
1159+
let modes = if self.binding_mode_count > 0 {
1160+
match kind {
1161+
Subtractive => {
1162+
format!("binding modifier{}", pluralize!(self.binding_mode_count))
1163+
}
1164+
Additive => {
1165+
format!("variable binding mode{}", pluralize!(self.binding_mode_count))
1166+
}
1167+
}
1168+
} else {
1169+
String::new()
1170+
};
1171+
let and = if !derefs.is_empty() && !modes.is_empty() { " and " } else { "" };
1172+
match kind {
1173+
Subtractive => format!("remove the unnecessary {derefs}{and}{modes}"),
1174+
Additive => {
1175+
format!("make the implied {derefs}{and}{modes} explicit")
1176+
}
1177+
}
1178+
} else {
1179+
"rewrite the pattern".to_owned()
11571180
};
11581181
// FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!)
11591182
if !self.suggestion.is_empty() {

0 commit comments

Comments
 (0)