@@ -5,9 +5,9 @@ use crate::diagnostics::error::{
5
5
DiagnosticDeriveError ,
6
6
} ;
7
7
use crate :: diagnostics:: utils:: {
8
- bind_style_of_field , build_field_mapping, report_error_if_not_applied_to_span,
9
- report_type_error , should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo ,
10
- FieldInnerTy , FieldMap , HasFieldMap , SetOnce , SpannedOption , SubdiagnosticKind ,
8
+ build_field_mapping, report_error_if_not_applied_to_span, report_type_error ,
9
+ should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo , FieldInnerTy , FieldMap ,
10
+ HasFieldMap , SetOnce , SpannedOption , SubdiagnosticKind ,
11
11
} ;
12
12
use proc_macro2:: { Ident , Span , TokenStream } ;
13
13
use quote:: { format_ident, quote} ;
@@ -40,6 +40,9 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
40
40
/// The parent builder for the entire type.
41
41
pub parent : & ' parent DiagnosticDeriveBuilder ,
42
42
43
+ /// Initialization of format strings for code suggestions.
44
+ pub formatting_init : TokenStream ,
45
+
43
46
/// Span of the struct or the enum variant.
44
47
pub span : proc_macro:: Span ,
45
48
@@ -88,19 +91,7 @@ impl DiagnosticDeriveBuilder {
88
91
}
89
92
}
90
93
91
- for variant in structure. variants_mut ( ) {
92
- // First, change the binding style of each field based on the code that will be
93
- // generated for the field - e.g. `set_arg` calls needs by-move bindings, whereas
94
- // `set_primary_span` only needs by-ref.
95
- variant. bind_with ( |bi| bind_style_of_field ( bi. ast ( ) ) . 0 ) ;
96
-
97
- // Then, perform a stable sort on bindings which generates code for by-ref bindings
98
- // before code generated for by-move bindings. Any code generated for the by-ref
99
- // bindings which creates a reference to the by-move fields will happen before the
100
- // by-move bindings move those fields and make them inaccessible.
101
- variant. bindings_mut ( ) . sort_by_cached_key ( |bi| bind_style_of_field ( bi. ast ( ) ) ) ;
102
- }
103
-
94
+ structure. bind_with ( |_| synstructure:: BindStyle :: Move ) ;
104
95
let variants = structure. each_variant ( |variant| {
105
96
let span = match structure. ast ( ) . data {
106
97
syn:: Data :: Struct ( ..) => span,
@@ -112,6 +103,7 @@ impl DiagnosticDeriveBuilder {
112
103
parent : & self ,
113
104
span,
114
105
field_map : build_field_mapping ( variant) ,
106
+ formatting_init : TokenStream :: new ( ) ,
115
107
slug : None ,
116
108
code : None ,
117
109
} ;
@@ -143,16 +135,14 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
143
135
144
136
/// Generates calls to `span_label` and similar functions based on the attributes on fields or
145
137
/// calls to `set_arg` when no attributes are present.
146
- ///
147
- /// Expects use of `Self::each_variant` which will have sorted bindings so that by-ref bindings
148
- /// (which may create references to by-move bindings) have their code generated first -
149
- /// necessary as code for suggestions uses formatting machinery and the value of other fields
150
- /// (any given field can be referenced multiple times, so must be accessed through a borrow);
151
- /// and when passing fields to `add_subdiagnostic` or `set_arg` for Fluent, fields must be
152
- /// accessed by-move.
153
138
pub fn body < ' s > ( & mut self , variant : & VariantInfo < ' s > ) -> TokenStream {
154
139
let mut body = quote ! { } ;
155
- for binding in variant. bindings ( ) {
140
+ // Generate `set_arg` calls first..
141
+ for binding in variant. bindings ( ) . iter ( ) . filter ( |bi| should_generate_set_arg ( bi. ast ( ) ) ) {
142
+ body. extend ( self . generate_field_code ( binding) ) ;
143
+ }
144
+ // ..and then subdiagnostic additions.
145
+ for binding in variant. bindings ( ) . iter ( ) . filter ( |bi| !should_generate_set_arg ( bi. ast ( ) ) ) {
156
146
body. extend ( self . generate_field_attrs_code ( binding) ) ;
157
147
}
158
148
body
@@ -274,24 +264,27 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
274
264
}
275
265
}
276
266
277
- fn generate_field_attrs_code ( & mut self , binding_info : & BindingInfo < ' _ > ) -> TokenStream {
267
+ fn generate_field_code ( & mut self , binding_info : & BindingInfo < ' _ > ) -> TokenStream {
268
+ let diag = & self . parent . diag ;
269
+
278
270
let field = binding_info. ast ( ) ;
279
271
let field_binding = & binding_info. binding ;
280
272
281
- if should_generate_set_arg ( & field) {
282
- let diag = & self . parent . diag ;
283
- let ident = field. ident . as_ref ( ) . unwrap ( ) ;
284
- // strip `r#` prefix, if present
285
- let ident = format_ident ! ( "{}" , ident) ;
286
- return quote ! {
287
- #diag. set_arg(
288
- stringify!( #ident) ,
289
- #field_binding
290
- ) ;
291
- } ;
273
+ let ident = field. ident . as_ref ( ) . unwrap ( ) ;
274
+ let ident = format_ident ! ( "{}" , ident) ; // strip `r#` prefix, if present
275
+
276
+ quote ! {
277
+ #diag. set_arg(
278
+ stringify!( #ident) ,
279
+ #field_binding
280
+ ) ;
292
281
}
282
+ }
283
+
284
+ fn generate_field_attrs_code ( & mut self , binding_info : & BindingInfo < ' _ > ) -> TokenStream {
285
+ let field = binding_info. ast ( ) ;
286
+ let field_binding = & binding_info. binding ;
293
287
294
- let needs_move = bind_style_of_field ( & field) . is_move ( ) ;
295
288
let inner_ty = FieldInnerTy :: from_type ( & field. ty ) ;
296
289
297
290
field
@@ -304,10 +297,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
304
297
let ( binding, needs_destructure) = if needs_clone {
305
298
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
306
299
( quote ! { #field_binding. clone( ) } , false )
307
- } else if needs_move {
308
- ( quote ! { #field_binding } , true )
309
300
} else {
310
- ( quote ! { * #field_binding } , true )
301
+ ( quote ! { #field_binding } , true )
311
302
} ;
312
303
313
304
let generated_code = self
@@ -440,8 +431,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
440
431
. unwrap_or_else ( || quote ! { rustc_errors:: Applicability :: Unspecified } ) ;
441
432
let style = suggestion_kind. to_suggestion_style ( ) ;
442
433
434
+ self . formatting_init . extend ( code_init) ;
443
435
Ok ( quote ! {
444
- #code_init
445
436
#diag. span_suggestion_with_style(
446
437
#span_field,
447
438
rustc_errors:: fluent:: #slug,
@@ -490,7 +481,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
490
481
// If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
491
482
ty @ Type :: Path ( ..) if type_matches_path ( ty, & [ "rustc_span" , "Span" ] ) => {
492
483
let binding = & info. binding . binding ;
493
- Ok ( ( quote ! ( * #binding) , None ) )
484
+ Ok ( ( quote ! ( #binding) , None ) )
494
485
}
495
486
// If `ty` is `(Span, Applicability)` then return tokens accessing those.
496
487
Type :: Tuple ( tup) => {
0 commit comments