Skip to content

Commit b4ac262

Browse files
committed
errors: AddToDiagnostic::add_to_diagnostic_with
`AddToDiagnostic::add_to_diagnostic_with` is similar to the previous `AddToDiagnostic::add_to_diagnostic` but takes a function that can be used by the caller to modify diagnostic messages originating from the subdiagnostic (such as performing translation eagerly). `add_to_diagnostic` now just calls `add_to_diagnostic_with` with an empty closure. Signed-off-by: David Wood <[email protected]>
1 parent 508d7e6 commit b4ac262

File tree

11 files changed

+129
-50
lines changed

11 files changed

+129
-50
lines changed

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay};
1+
use rustc_errors::{
2+
fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay,
3+
SubdiagnosticMessage,
4+
};
25
use rustc_macros::{Diagnostic, Subdiagnostic};
36
use rustc_span::{symbol::Ident, Span, Symbol};
47

@@ -19,7 +22,10 @@ pub struct UseAngleBrackets {
1922
}
2023

2124
impl AddToDiagnostic for UseAngleBrackets {
22-
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
25+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
26+
where
27+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
28+
{
2329
diag.multipart_suggestion(
2430
fluent::ast_lowering::use_angle_brackets,
2531
vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
@@ -69,7 +75,10 @@ pub enum AssocTyParenthesesSub {
6975
}
7076

7177
impl AddToDiagnostic for AssocTyParenthesesSub {
72-
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
78+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
79+
where
80+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
81+
{
7382
match self {
7483
Self::Empty { parentheses_span } => diag.multipart_suggestion(
7584
fluent::ast_lowering::remove_parentheses,

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Errors emitted by ast_passes.
22
3-
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic};
3+
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
44
use rustc_macros::{Diagnostic, Subdiagnostic};
55
use rustc_span::{Span, Symbol};
66

@@ -17,7 +17,10 @@ pub struct ForbiddenLet {
1717
}
1818

1919
impl AddToDiagnostic for ForbiddenLetReason {
20-
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
20+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
21+
where
22+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
23+
{
2124
match self {
2225
Self::GenericForbidden => {}
2326
Self::NotSupportedOr(span) => {
@@ -228,7 +231,10 @@ pub struct ExternBlockSuggestion {
228231
}
229232

230233
impl AddToDiagnostic for ExternBlockSuggestion {
231-
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
234+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
235+
where
236+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
237+
{
232238
let start_suggestion = if let Some(abi) = self.abi {
233239
format!("extern \"{}\" {{", abi)
234240
} else {

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,20 @@ impl IntoDiagnosticArg for ast::token::TokenKind {
203203
/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
204204
#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
205205
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
206-
pub trait AddToDiagnostic {
206+
pub trait AddToDiagnostic
207+
where
208+
Self: Sized,
209+
{
207210
/// Add a subdiagnostic to an existing diagnostic.
208-
fn add_to_diagnostic(self, diag: &mut Diagnostic);
211+
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
212+
self.add_to_diagnostic_with(diag, |_, m| m);
213+
}
214+
215+
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
216+
/// (to optionally perform eager translation).
217+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
218+
where
219+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage;
209220
}
210221

211222
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
@@ -921,8 +932,8 @@ impl Diagnostic {
921932
self
922933
}
923934

924-
/// Add a subdiagnostic from a type that implements `Subdiagnostic` - see
925-
/// [rustc_macros::Subdiagnostic].
935+
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
936+
/// [rustc_macros::Subdiagnostic]).
926937
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
927938
subdiagnostic.add_to_diagnostic(self);
928939
self

compiler/rustc_infer/src/errors/mod.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use hir::GenericParamKind;
22
use rustc_errors::{
3-
fluent, AddToDiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
3+
fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
4+
MultiSpan, SubdiagnosticMessage,
45
};
56
use rustc_hir as hir;
67
use rustc_hir::{FnRetTy, Ty};
@@ -229,7 +230,10 @@ pub enum RegionOriginNote<'a> {
229230
}
230231

231232
impl AddToDiagnostic for RegionOriginNote<'_> {
232-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
233+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
234+
where
235+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
236+
{
233237
let mut label_or_note = |span, msg: DiagnosticMessage| {
234238
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
235239
let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
@@ -290,7 +294,10 @@ pub enum LifetimeMismatchLabels {
290294
}
291295

292296
impl AddToDiagnostic for LifetimeMismatchLabels {
293-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
297+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
298+
where
299+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
300+
{
294301
match self {
295302
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
296303
diag.span_label(param_span, fluent::infer::declared_different);
@@ -340,7 +347,10 @@ pub struct AddLifetimeParamsSuggestion<'a> {
340347
}
341348

342349
impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
343-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
350+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
351+
where
352+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
353+
{
344354
let mut mk_suggestion = || {
345355
let (
346356
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
@@ -439,7 +449,10 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
439449
}
440450

441451
impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
442-
fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
452+
fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
453+
where
454+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
455+
{
443456
self.unmet_requirements
444457
.push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
445458
diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
@@ -451,7 +464,10 @@ pub struct ImplNote {
451464
}
452465

453466
impl AddToDiagnostic for ImplNote {
454-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
467+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
468+
where
469+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
470+
{
455471
match self.impl_span {
456472
Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
457473
None => diag.note(fluent::infer::msl_impl_note),
@@ -466,7 +482,10 @@ pub enum TraitSubdiag {
466482

467483
// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
468484
impl AddToDiagnostic for TraitSubdiag {
469-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
485+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
486+
where
487+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
488+
{
470489
match self {
471490
TraitSubdiag::Note { span } => {
472491
diag.span_note(span, "this has an implicit `'static` lifetime requirement");

compiler/rustc_infer/src/errors/note_and_explain.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::infer::error_reporting::nice_region_error::find_anon_type;
2-
use rustc_errors::{self, fluent, AddToDiagnostic, IntoDiagnosticArg};
2+
use rustc_errors::{
3+
self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
4+
};
35
use rustc_middle::ty::{self, TyCtxt};
46
use rustc_span::{symbol::kw, Span};
57

@@ -159,7 +161,10 @@ impl RegionExplanation<'_> {
159161
}
160162

161163
impl AddToDiagnostic for RegionExplanation<'_> {
162-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
164+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
165+
where
166+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
167+
{
163168
if let Some(span) = self.desc.span {
164169
diag.span_note(span, fluent::infer::region_explanation);
165170
} else {

compiler/rustc_lint/src/errors.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use rustc_errors::{fluent, AddToDiagnostic, ErrorGuaranteed, Handler, IntoDiagnostic};
1+
use rustc_errors::{
2+
fluent, AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
3+
SubdiagnosticMessage,
4+
};
25
use rustc_macros::{Diagnostic, Subdiagnostic};
36
use rustc_session::lint::Level;
47
use rustc_span::{Span, Symbol};
@@ -23,7 +26,10 @@ pub enum OverruledAttributeSub {
2326
}
2427

2528
impl AddToDiagnostic for OverruledAttributeSub {
26-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
29+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
30+
where
31+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
32+
{
2733
match self {
2834
OverruledAttributeSub::DefaultSource { id } => {
2935
diag.note(fluent::lint::default_source);
@@ -88,7 +94,10 @@ pub struct RequestedLevel {
8894
}
8995

9096
impl AddToDiagnostic for RequestedLevel {
91-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
97+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
98+
where
99+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
100+
{
92101
diag.note(fluent::lint::requested_level);
93102
diag.set_arg(
94103
"level",

compiler/rustc_macros/src/diagnostics/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
99
pub(crate) use fluent::fluent_messages;
1010
use proc_macro2::TokenStream;
1111
use quote::format_ident;
12-
use subdiagnostic::SubdiagnosticDerive;
12+
use subdiagnostic::SubdiagnosticDeriveBuilder;
1313
use synstructure::Structure;
1414

1515
/// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
@@ -155,5 +155,5 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
155155
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
156156
/// ```
157157
pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
158-
SubdiagnosticDerive::new(s).into_tokens()
158+
SubdiagnosticDeriveBuilder::new().into_tokens(s)
159159
}

compiler/rustc_macros/src/diagnostics/subdiagnostic.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta
1515
use synstructure::{BindingInfo, Structure, VariantInfo};
1616

1717
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
18-
pub(crate) struct SubdiagnosticDerive<'a> {
19-
structure: Structure<'a>,
18+
pub(crate) struct SubdiagnosticDeriveBuilder {
2019
diag: syn::Ident,
20+
f: syn::Ident,
2121
}
2222

23-
impl<'a> SubdiagnosticDerive<'a> {
24-
pub(crate) fn new(structure: Structure<'a>) -> Self {
23+
impl SubdiagnosticDeriveBuilder {
24+
pub(crate) fn new() -> Self {
2525
let diag = format_ident!("diag");
26-
Self { structure, diag }
26+
let f = format_ident!("f");
27+
Self { diag, f }
2728
}
2829

29-
pub(crate) fn into_tokens(self) -> TokenStream {
30-
let SubdiagnosticDerive { mut structure, diag } = self;
30+
pub(crate) fn into_tokens<'a>(self, mut structure: Structure<'a>) -> TokenStream {
3131
let implementation = {
3232
let ast = structure.ast();
3333
let span = ast.span().unwrap();
@@ -53,8 +53,8 @@ impl<'a> SubdiagnosticDerive<'a> {
5353

5454
structure.bind_with(|_| synstructure::BindStyle::Move);
5555
let variants_ = structure.each_variant(|variant| {
56-
let mut builder = SubdiagnosticDeriveBuilder {
57-
diag: &diag,
56+
let mut builder = SubdiagnosticDeriveVariantBuilder {
57+
parent: &self,
5858
variant,
5959
span,
6060
fields: build_field_mapping(variant),
@@ -72,9 +72,17 @@ impl<'a> SubdiagnosticDerive<'a> {
7272
}
7373
};
7474

75+
let diag = &self.diag;
76+
let f = &self.f;
7577
let ret = structure.gen_impl(quote! {
7678
gen impl rustc_errors::AddToDiagnostic for @Self {
77-
fn add_to_diagnostic(self, #diag: &mut rustc_errors::Diagnostic) {
79+
fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F)
80+
where
81+
__F: Fn(
82+
&mut rustc_errors::Diagnostic,
83+
rustc_errors::SubdiagnosticMessage
84+
) -> rustc_errors::SubdiagnosticMessage,
85+
{
7886
use rustc_errors::{Applicability, IntoDiagnosticArg};
7987
#implementation
8088
}
@@ -88,9 +96,9 @@ impl<'a> SubdiagnosticDerive<'a> {
8896
/// for the final generated method. This is a separate struct to `SubdiagnosticDerive`
8997
/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
9098
/// double mut borrow later on.
91-
struct SubdiagnosticDeriveBuilder<'a> {
99+
struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
92100
/// The identifier to use for the generated `DiagnosticBuilder` instance.
93-
diag: &'a syn::Ident,
101+
parent: &'parent SubdiagnosticDeriveBuilder,
94102

95103
/// Info for the current variant (or the type if not an enum).
96104
variant: &'a VariantInfo<'a>,
@@ -112,7 +120,7 @@ struct SubdiagnosticDeriveBuilder<'a> {
112120
has_suggestion_parts: bool,
113121
}
114122

115-
impl<'a> HasFieldMap for SubdiagnosticDeriveBuilder<'a> {
123+
impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
116124
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
117125
self.fields.get(field)
118126
}
@@ -156,7 +164,7 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
156164
}
157165
}
158166

159-
impl<'a> SubdiagnosticDeriveBuilder<'a> {
167+
impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
160168
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
161169
let mut kind_slugs = vec![];
162170

@@ -187,7 +195,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
187195
let ast = binding.ast();
188196
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
189197

190-
let diag = &self.diag;
198+
let diag = &self.parent.diag;
191199
let ident = ast.ident.as_ref().unwrap();
192200
// strip `r#` prefix, if present
193201
let ident = format_ident!("{}", ident);
@@ -442,11 +450,14 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
442450

443451
let span_field = self.span_field.value_ref();
444452

445-
let diag = &self.diag;
453+
let diag = &self.parent.diag;
454+
let f = &self.parent.f;
446455
let mut calls = TokenStream::new();
447456
for (kind, slug) in kind_slugs {
457+
let message = format_ident!("__message");
458+
calls.extend(quote! { let #message = #f(#diag, rustc_errors::fluent::#slug.into()); });
459+
448460
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
449-
let message = quote! { rustc_errors::fluent::#slug };
450461
let call = match kind {
451462
SubdiagnosticKind::Suggestion { suggestion_kind, applicability, code } => {
452463
let applicability = applicability

compiler/rustc_query_system/src/error.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_errors::AddToDiagnostic;
1+
use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage};
22
use rustc_macros::{Diagnostic, Subdiagnostic};
33
use rustc_session::Limit;
44
use rustc_span::{Span, Symbol};
@@ -9,7 +9,10 @@ pub struct CycleStack {
99
}
1010

1111
impl AddToDiagnostic for CycleStack {
12-
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
12+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
13+
where
14+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
15+
{
1316
diag.span_note(self.span, &format!("...which requires {}...", self.desc));
1417
}
1518
}

0 commit comments

Comments
 (0)