Skip to content

Commit 8ea73c4

Browse files
committed
clean up match ergonomics diagnostic code
Only some of it was using fluent, so this makes it fully untranslatable.
1 parent 19fd125 commit 8ea73c4

File tree

3 files changed

+79
-125
lines changed

3 files changed

+79
-125
lines changed

compiler/rustc_mir_build/messages.ftl

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -318,29 +318,6 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
318318
319319
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
320320
321-
mir_build_rust_2024_incompatible_pat = cannot {$bad_mut_modifiers ->
322-
*[true] {$bad_ref_modifiers ->
323-
*[true] write explicit binding modifiers
324-
[false] mutably bind by value
325-
}{$bad_ref_pats ->
326-
*[true] {" "}or explicitly dereference
327-
[false] {""}
328-
}
329-
[false] {$bad_ref_modifiers ->
330-
*[true] explicitly borrow{$bad_ref_pats ->
331-
*[true] {" "}or dereference
332-
[false] {""}
333-
}
334-
[false] {$bad_ref_pats ->
335-
*[true] explicitly dereference
336-
[false] {""}
337-
}
338-
}
339-
} within an implicitly-borrowing pattern{$is_hard_error ->
340-
*[true] {""}
341-
[false] {" "}in Rust 2024
342-
}
343-
344321
mir_build_static_in_pattern = statics cannot be referenced in patterns
345322
.label = can't be used in patterns
346323
mir_build_static_in_pattern_def = `static` defined here

compiler/rustc_mir_build/src/errors.rs

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use rustc_data_structures::fx::FxIndexMap;
21
use rustc_errors::codes::*;
32
use rustc_errors::{
43
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
5-
MultiSpan, Subdiagnostic, pluralize,
4+
MultiSpan, Subdiagnostic,
65
};
76
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
87
use rustc_middle::ty::{self, Ty};
@@ -1096,76 +1095,6 @@ pub(crate) enum MiscPatternSuggestion {
10961095
},
10971096
}
10981097

1099-
#[derive(LintDiagnostic)]
1100-
#[diag(mir_build_rust_2024_incompatible_pat)]
1101-
pub(crate) struct Rust2024IncompatiblePat {
1102-
#[subdiagnostic]
1103-
pub(crate) sugg: Rust2024IncompatiblePatSugg,
1104-
pub(crate) bad_mut_modifiers: bool,
1105-
pub(crate) bad_ref_modifiers: bool,
1106-
pub(crate) bad_ref_pats: bool,
1107-
pub(crate) is_hard_error: bool,
1108-
}
1109-
1110-
pub(crate) struct Rust2024IncompatiblePatSugg {
1111-
/// If true, our suggestion is to elide explicit binding modifiers.
1112-
/// If false, our suggestion is to make the pattern fully explicit.
1113-
pub(crate) suggest_eliding_modes: bool,
1114-
pub(crate) suggestion: Vec<(Span, String)>,
1115-
pub(crate) ref_pattern_count: usize,
1116-
pub(crate) binding_mode_count: usize,
1117-
/// Labels for where incompatibility-causing by-ref default binding modes were introduced.
1118-
pub(crate) default_mode_labels: FxIndexMap<Span, ty::Mutability>,
1119-
}
1120-
1121-
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
1122-
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1123-
// Format and emit explanatory notes about default binding modes. Reversing the spans' order
1124-
// means if we have nested spans, the innermost ones will be visited first.
1125-
for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() {
1126-
// Don't point to a macro call site.
1127-
if !span.from_expansion() {
1128-
let note_msg = "matching on a reference type with a non-reference pattern implicitly borrows the contents";
1129-
let label_msg = format!(
1130-
"this non-reference pattern matches on a reference type `{}_`",
1131-
def_br_mutbl.ref_prefix_str()
1132-
);
1133-
let mut label = MultiSpan::from(span);
1134-
label.push_span_label(span, label_msg);
1135-
diag.span_note(label, note_msg);
1136-
}
1137-
}
1138-
1139-
// Format and emit the suggestion.
1140-
let applicability =
1141-
if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
1142-
Applicability::MachineApplicable
1143-
} else {
1144-
Applicability::MaybeIncorrect
1145-
};
1146-
let plural_modes = pluralize!(self.binding_mode_count);
1147-
let msg = if self.suggest_eliding_modes {
1148-
format!("remove the unnecessary binding modifier{plural_modes}")
1149-
} else {
1150-
let and_add_modes = if self.binding_mode_count > 0 {
1151-
let a = if self.binding_mode_count == 1 { "a " } else { "" };
1152-
format!(" and borrow explicitly using {a}variable binding mode{plural_modes}",)
1153-
} else {
1154-
String::new()
1155-
};
1156-
if self.ref_pattern_count == 1 {
1157-
format!("match on the reference with a reference pattern{and_add_modes}")
1158-
} else {
1159-
format!("match on these references with reference patterns{and_add_modes}")
1160-
}
1161-
};
1162-
// FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!)
1163-
if !self.suggestion.is_empty() {
1164-
diag.multipart_suggestion_verbose(msg, self.suggestion, applicability);
1165-
}
1166-
}
1167-
}
1168-
11691098
#[derive(Diagnostic)]
11701099
#[diag(mir_build_loop_match_invalid_update)]
11711100
pub(crate) struct LoopMatchInvalidUpdate {

compiler/rustc_mir_build/src/thir/pattern/migration.rs

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
//! Automatic migration of Rust 2021 patterns to a form valid in both Editions 2021 and 2024.
22
33
use rustc_data_structures::fx::FxIndexMap;
4-
use rustc_errors::MultiSpan;
4+
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize};
55
use rustc_hir::{BindingMode, ByRef, HirId, Mutability};
66
use rustc_lint as lint;
77
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt};
88
use rustc_span::{Ident, Span};
99

10-
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
11-
use crate::fluent_generated as fluent;
12-
1310
/// For patterns flagged for migration during HIR typeck, this handles constructing and emitting
1411
/// a diagnostic suggestion.
1512
pub(super) struct PatMigration<'a> {
@@ -49,41 +46,92 @@ impl<'a> PatMigration<'a> {
4946
for (span, label) in self.info.primary_labels.iter() {
5047
spans.push_span_label(*span, label.clone());
5148
}
52-
let sugg = Rust2024IncompatiblePatSugg {
53-
suggest_eliding_modes: self.info.suggest_eliding_modes,
54-
suggestion: self.suggestion,
55-
ref_pattern_count: self.ref_pattern_count,
56-
binding_mode_count: self.binding_mode_count,
57-
default_mode_labels: self.default_mode_labels,
58-
};
5949
// If a relevant span is from at least edition 2024, this is a hard error.
6050
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
51+
let primary_message = self.primary_message(is_hard_error);
6152
if is_hard_error {
62-
let mut err =
63-
tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
53+
let mut err = tcx.dcx().struct_span_err(spans, primary_message);
6454
if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
6555
// provide the same reference link as the lint
6656
err.note(format!("for more information, see {}", info.reference));
6757
}
68-
err.arg("bad_mut_modifiers", self.info.bad_mut_modifiers);
69-
err.arg("bad_ref_modifiers", self.info.bad_ref_modifiers);
70-
err.arg("bad_ref_pats", self.info.bad_ref_pats);
71-
err.arg("is_hard_error", true);
72-
err.subdiagnostic(sugg);
58+
self.format_subdiagnostics(&mut err);
7359
err.emit();
7460
} else {
75-
tcx.emit_node_span_lint(
76-
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
77-
pat_id,
78-
spans,
79-
Rust2024IncompatiblePat {
80-
sugg,
81-
bad_mut_modifiers: self.info.bad_mut_modifiers,
82-
bad_ref_modifiers: self.info.bad_ref_modifiers,
83-
bad_ref_pats: self.info.bad_ref_pats,
84-
is_hard_error,
85-
},
86-
);
61+
tcx.node_span_lint(lint::builtin::RUST_2024_INCOMPATIBLE_PAT, pat_id, spans, |diag| {
62+
diag.primary_message(primary_message);
63+
self.format_subdiagnostics(diag);
64+
});
65+
}
66+
}
67+
68+
fn primary_message(&self, is_hard_error: bool) -> String {
69+
let verb1 = match (self.info.bad_mut_modifiers, self.info.bad_ref_modifiers) {
70+
(true, true) => "write explicit binding modifiers",
71+
(true, false) => "mutably bind by value",
72+
(false, true) => "explicitly borrow",
73+
(false, false) => "explicitly dereference",
74+
};
75+
let or_verb2 = match (
76+
self.info.bad_mut_modifiers,
77+
self.info.bad_ref_modifiers,
78+
self.info.bad_ref_pats,
79+
) {
80+
// We only need two verb phrases if mentioning both modifiers and reference patterns.
81+
(false, false, _) | (_, _, false) => "",
82+
// If mentioning `mut`, we don't have an "explicitly" yet.
83+
(true, _, true) => " or explicitly dereference",
84+
// If mentioning `ref`/`ref mut` but not `mut`, we already have an "explicitly".
85+
(false, true, true) => " or dereference",
86+
};
87+
let in_rust_2024 = if is_hard_error { "" } else { " in Rust 2024" };
88+
format!("cannot {verb1}{or_verb2} within an implicitly-borrowing pattern{in_rust_2024}")
89+
}
90+
91+
fn format_subdiagnostics(self, diag: &mut Diag<'_, impl EmissionGuarantee>) {
92+
// Format and emit explanatory notes about default binding modes. Reversing the spans' order
93+
// means if we have nested spans, the innermost ones will be visited first.
94+
for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() {
95+
// Don't point to a macro call site.
96+
if !span.from_expansion() {
97+
let note_msg = "matching on a reference type with a non-reference pattern implicitly borrows the contents";
98+
let label_msg = format!(
99+
"this non-reference pattern matches on a reference type `{}_`",
100+
def_br_mutbl.ref_prefix_str()
101+
);
102+
let mut label = MultiSpan::from(span);
103+
label.push_span_label(span, label_msg);
104+
diag.span_note(label, note_msg);
105+
}
106+
}
107+
108+
// Format and emit the suggestion.
109+
let applicability =
110+
if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
111+
Applicability::MachineApplicable
112+
} else {
113+
Applicability::MaybeIncorrect
114+
};
115+
let plural_modes = pluralize!(self.binding_mode_count);
116+
let msg = if self.info.suggest_eliding_modes {
117+
format!("remove the unnecessary binding modifier{plural_modes}")
118+
} else {
119+
let and_add_modes = if self.binding_mode_count > 0 {
120+
let a = if self.binding_mode_count == 1 { "a " } else { "" };
121+
format!(" and borrow explicitly using {a}variable binding mode{plural_modes}",)
122+
} else {
123+
String::new()
124+
};
125+
if self.ref_pattern_count == 1 {
126+
format!("match on the reference with a reference pattern{and_add_modes}")
127+
} else {
128+
format!("match on these references with reference patterns{and_add_modes}")
129+
}
130+
};
131+
// FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!)
132+
debug_assert!(!self.suggestion.is_empty());
133+
if !self.suggestion.is_empty() {
134+
diag.multipart_suggestion_verbose(msg, self.suggestion, applicability);
87135
}
88136
}
89137

0 commit comments

Comments
 (0)