Skip to content

Commit de0b511

Browse files
committed
Auto merge of #102189 - davidtwco:translation-derive-enums, r=compiler-errors
macros: diagnostic derive on enums Part of #100717. Extends `#[derive(Diagnostic)]` to work on enums too where each variant acts like a distinct diagnostic - being able to represent diagnostics this way can be quite a bit simpler for some parts of the compiler. r? `@compiler-errors` cc `@Xiretza`
2 parents cd4d9d9 + f20c882 commit de0b511

File tree

6 files changed

+371
-308
lines changed

6 files changed

+371
-308
lines changed

compiler/rustc_macros/src/diagnostics/diagnostic.rs

+54-103
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
44
use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
5-
use crate::diagnostics::utils::{build_field_mapping, SetOnce};
5+
use crate::diagnostics::utils::SetOnce;
66
use proc_macro2::TokenStream;
77
use quote::quote;
8-
use syn::spanned::Spanned;
98
use synstructure::Structure;
109

1110
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
@@ -18,13 +17,7 @@ pub(crate) struct DiagnosticDerive<'a> {
1817
impl<'a> DiagnosticDerive<'a> {
1918
pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
2019
Self {
21-
builder: DiagnosticDeriveBuilder {
22-
diag,
23-
fields: build_field_mapping(&structure),
24-
kind: DiagnosticDeriveKind::Diagnostic,
25-
code: None,
26-
slug: None,
27-
},
20+
builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::Diagnostic },
2821
handler,
2922
structure,
3023
}
@@ -33,52 +26,35 @@ impl<'a> DiagnosticDerive<'a> {
3326
pub(crate) fn into_tokens(self) -> TokenStream {
3427
let DiagnosticDerive { mut structure, handler, mut builder } = self;
3528

36-
let ast = structure.ast();
37-
let implementation = {
38-
if let syn::Data::Struct(..) = ast.data {
39-
let preamble = builder.preamble(&structure);
40-
let (attrs, args) = builder.body(&mut structure);
41-
42-
let span = ast.span().unwrap();
43-
let diag = &builder.diag;
44-
let init = match builder.slug.value() {
45-
None => {
46-
span_err(span, "diagnostic slug not specified")
47-
.help(&format!(
48-
"specify the slug as the first argument to the `#[diag(...)]` attribute, \
49-
such as `#[diag(typeck::example_error)]`",
50-
))
51-
.emit();
52-
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
53-
}
54-
Some(slug) => {
55-
quote! {
56-
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
57-
}
58-
}
59-
};
60-
61-
quote! {
62-
#init
63-
#preamble
64-
match self {
65-
#attrs
66-
}
67-
match self {
68-
#args
29+
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
30+
let preamble = builder.preamble(&variant);
31+
let body = builder.body(&variant);
32+
33+
let diag = &builder.parent.diag;
34+
let init = match builder.slug.value_ref() {
35+
None => {
36+
span_err(builder.span, "diagnostic slug not specified")
37+
.help(&format!(
38+
"specify the slug as the first argument to the `#[diag(...)]` \
39+
attribute, such as `#[diag(typeck::example_error)]`",
40+
))
41+
.emit();
42+
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
43+
}
44+
Some(slug) => {
45+
quote! {
46+
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
6947
}
70-
#diag
7148
}
72-
} else {
73-
span_err(
74-
ast.span().unwrap(),
75-
"`#[derive(Diagnostic)]` can only be used on structs",
76-
)
77-
.emit();
49+
};
7850

79-
DiagnosticDeriveError::ErrorHandled.to_compile_error()
51+
quote! {
52+
#init
53+
#preamble
54+
#body
55+
#diag
8056
}
81-
};
57+
});
8258

8359
structure.gen_impl(quote! {
8460
gen impl<'__diagnostic_handler_sess, G>
@@ -107,68 +83,43 @@ pub(crate) struct LintDiagnosticDerive<'a> {
10783
impl<'a> LintDiagnosticDerive<'a> {
10884
pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self {
10985
Self {
110-
builder: DiagnosticDeriveBuilder {
111-
diag,
112-
fields: build_field_mapping(&structure),
113-
kind: DiagnosticDeriveKind::LintDiagnostic,
114-
code: None,
115-
slug: None,
116-
},
86+
builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::LintDiagnostic },
11787
structure,
11888
}
11989
}
12090

12191
pub(crate) fn into_tokens(self) -> TokenStream {
12292
let LintDiagnosticDerive { mut structure, mut builder } = self;
12393

124-
let ast = structure.ast();
125-
let implementation = {
126-
if let syn::Data::Struct(..) = ast.data {
127-
let preamble = builder.preamble(&structure);
128-
let (attrs, args) = builder.body(&mut structure);
129-
130-
let diag = &builder.diag;
131-
let span = ast.span().unwrap();
132-
let init = match builder.slug.value() {
133-
None => {
134-
span_err(span, "diagnostic slug not specified")
135-
.help(&format!(
136-
"specify the slug as the first argument to the attribute, such as \
137-
`#[diag(typeck::example_error)]`",
138-
))
139-
.emit();
140-
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
141-
}
142-
Some(slug) => {
143-
quote! {
144-
let mut #diag = #diag.build(rustc_errors::fluent::#slug);
145-
}
146-
}
147-
};
148-
149-
let implementation = quote! {
150-
#init
151-
#preamble
152-
match self {
153-
#attrs
154-
}
155-
match self {
156-
#args
94+
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
95+
let preamble = builder.preamble(&variant);
96+
let body = builder.body(&variant);
97+
98+
let diag = &builder.parent.diag;
99+
let init = match builder.slug.value_ref() {
100+
None => {
101+
span_err(builder.span, "diagnostic slug not specified")
102+
.help(&format!(
103+
"specify the slug as the first argument to the attribute, such as \
104+
`#[diag(typeck::example_error)]`",
105+
))
106+
.emit();
107+
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
108+
}
109+
Some(slug) => {
110+
quote! {
111+
let mut #diag = #diag.build(rustc_errors::fluent::#slug);
157112
}
158-
#diag.emit();
159-
};
160-
161-
implementation
162-
} else {
163-
span_err(
164-
ast.span().unwrap(),
165-
"`#[derive(LintDiagnostic)]` can only be used on structs",
166-
)
167-
.emit();
113+
}
114+
};
168115

169-
DiagnosticDeriveError::ErrorHandled.to_compile_error()
116+
quote! {
117+
#init
118+
#preamble
119+
#body
120+
#diag.emit();
170121
}
171-
};
122+
});
172123

173124
let diag = &builder.diag;
174125
structure.gen_impl(quote! {

0 commit comments

Comments
 (0)