@@ -15,19 +15,19 @@ use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta
15
15
use synstructure:: { BindingInfo , Structure , VariantInfo } ;
16
16
17
17
/// 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 {
20
19
diag : syn:: Ident ,
20
+ f : syn:: Ident ,
21
21
}
22
22
23
- impl < ' a > SubdiagnosticDerive < ' a > {
24
- pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
23
+ impl SubdiagnosticDeriveBuilder {
24
+ pub ( crate ) fn new ( ) -> Self {
25
25
let diag = format_ident ! ( "diag" ) ;
26
- Self { structure, diag }
26
+ let f = format_ident ! ( "f" ) ;
27
+ Self { diag, f }
27
28
}
28
29
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 {
31
31
let implementation = {
32
32
let ast = structure. ast ( ) ;
33
33
let span = ast. span ( ) . unwrap ( ) ;
@@ -53,8 +53,8 @@ impl<'a> SubdiagnosticDerive<'a> {
53
53
54
54
structure. bind_with ( |_| synstructure:: BindStyle :: Move ) ;
55
55
let variants_ = structure. each_variant ( |variant| {
56
- let mut builder = SubdiagnosticDeriveBuilder {
57
- diag : & diag ,
56
+ let mut builder = SubdiagnosticDeriveVariantBuilder {
57
+ parent : & self ,
58
58
variant,
59
59
span,
60
60
fields : build_field_mapping ( variant) ,
@@ -72,9 +72,17 @@ impl<'a> SubdiagnosticDerive<'a> {
72
72
}
73
73
} ;
74
74
75
+ let diag = & self . diag ;
76
+ let f = & self . f ;
75
77
let ret = structure. gen_impl ( quote ! {
76
78
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
+ {
78
86
use rustc_errors:: { Applicability , IntoDiagnosticArg } ;
79
87
#implementation
80
88
}
@@ -88,9 +96,9 @@ impl<'a> SubdiagnosticDerive<'a> {
88
96
/// for the final generated method. This is a separate struct to `SubdiagnosticDerive`
89
97
/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
90
98
/// double mut borrow later on.
91
- struct SubdiagnosticDeriveBuilder < ' a > {
99
+ struct SubdiagnosticDeriveVariantBuilder < ' parent , ' a > {
92
100
/// The identifier to use for the generated `DiagnosticBuilder` instance.
93
- diag : & ' a syn :: Ident ,
101
+ parent : & ' parent SubdiagnosticDeriveBuilder ,
94
102
95
103
/// Info for the current variant (or the type if not an enum).
96
104
variant : & ' a VariantInfo < ' a > ,
@@ -112,7 +120,7 @@ struct SubdiagnosticDeriveBuilder<'a> {
112
120
has_suggestion_parts : bool ,
113
121
}
114
122
115
- impl < ' a > HasFieldMap for SubdiagnosticDeriveBuilder < ' a > {
123
+ impl < ' parent , ' a > HasFieldMap for SubdiagnosticDeriveVariantBuilder < ' parent , ' a > {
116
124
fn get_field_binding ( & self , field : & String ) -> Option < & TokenStream > {
117
125
self . fields . get ( field)
118
126
}
@@ -156,7 +164,7 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
156
164
}
157
165
}
158
166
159
- impl < ' a > SubdiagnosticDeriveBuilder < ' a > {
167
+ impl < ' parent , ' a > SubdiagnosticDeriveVariantBuilder < ' parent , ' a > {
160
168
fn identify_kind ( & mut self ) -> Result < Vec < ( SubdiagnosticKind , Path ) > , DiagnosticDeriveError > {
161
169
let mut kind_slugs = vec ! [ ] ;
162
170
@@ -187,7 +195,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
187
195
let ast = binding. ast ( ) ;
188
196
assert_eq ! ( ast. attrs. len( ) , 0 , "field with attribute used as diagnostic arg" ) ;
189
197
190
- let diag = & self . diag ;
198
+ let diag = & self . parent . diag ;
191
199
let ident = ast. ident . as_ref ( ) . unwrap ( ) ;
192
200
// strip `r#` prefix, if present
193
201
let ident = format_ident ! ( "{}" , ident) ;
@@ -442,11 +450,14 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
442
450
443
451
let span_field = self . span_field . value_ref ( ) ;
444
452
445
- let diag = & self . diag ;
453
+ let diag = & self . parent . diag ;
454
+ let f = & self . parent . f ;
446
455
let mut calls = TokenStream :: new ( ) ;
447
456
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
+
448
460
let name = format_ident ! ( "{}{}" , if span_field. is_some( ) { "span_" } else { "" } , kind) ;
449
- let message = quote ! { rustc_errors:: fluent:: #slug } ;
450
461
let call = match kind {
451
462
SubdiagnosticKind :: Suggestion { suggestion_kind, applicability, code } => {
452
463
let applicability = applicability
0 commit comments