@@ -5,9 +5,9 @@ use crate::diagnostics::error::{
55 DiagnosticDeriveError ,
66} ;
77use 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 ,
1111} ;
1212use proc_macro2:: { Ident , Span , TokenStream } ;
1313use quote:: { format_ident, quote} ;
@@ -40,6 +40,9 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
4040 /// The parent builder for the entire type.
4141 pub parent : & ' parent DiagnosticDeriveBuilder ,
4242
43+ /// Initialization of format strings for code suggestions.
44+ pub formatting_init : TokenStream ,
45+
4346 /// Span of the struct or the enum variant.
4447 pub span : proc_macro:: Span ,
4548
@@ -88,19 +91,7 @@ impl DiagnosticDeriveBuilder {
8891 }
8992 }
9093
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 ) ;
10495 let variants = structure. each_variant ( |variant| {
10596 let span = match structure. ast ( ) . data {
10697 syn:: Data :: Struct ( ..) => span,
@@ -112,6 +103,7 @@ impl DiagnosticDeriveBuilder {
112103 parent : & self ,
113104 span,
114105 field_map : build_field_mapping ( variant) ,
106+ formatting_init : TokenStream :: new ( ) ,
115107 slug : None ,
116108 code : None ,
117109 } ;
@@ -143,16 +135,14 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
143135
144136 /// Generates calls to `span_label` and similar functions based on the attributes on fields or
145137 /// 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.
153138 pub fn body < ' s > ( & mut self , variant : & VariantInfo < ' s > ) -> TokenStream {
154139 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 ( ) ) ) {
156146 body. extend ( self . generate_field_attrs_code ( binding) ) ;
157147 }
158148 body
@@ -274,24 +264,27 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
274264 }
275265 }
276266
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+
278270 let field = binding_info. ast ( ) ;
279271 let field_binding = & binding_info. binding ;
280272
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+ ) ;
292281 }
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 ;
293287
294- let needs_move = bind_style_of_field ( & field) . is_move ( ) ;
295288 let inner_ty = FieldInnerTy :: from_type ( & field. ty ) ;
296289
297290 field
@@ -304,10 +297,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
304297 let ( binding, needs_destructure) = if needs_clone {
305298 // `primary_span` can accept a `Vec<Span>` so don't destructure that.
306299 ( quote ! { #field_binding. clone( ) } , false )
307- } else if needs_move {
308- ( quote ! { #field_binding } , true )
309300 } else {
310- ( quote ! { * #field_binding } , true )
301+ ( quote ! { #field_binding } , true )
311302 } ;
312303
313304 let generated_code = self
@@ -440,8 +431,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
440431 . unwrap_or_else ( || quote ! { rustc_errors:: Applicability :: Unspecified } ) ;
441432 let style = suggestion_kind. to_suggestion_style ( ) ;
442433
434+ self . formatting_init . extend ( code_init) ;
443435 Ok ( quote ! {
444- #code_init
445436 #diag. span_suggestion_with_style(
446437 #span_field,
447438 rustc_errors:: fluent:: #slug,
@@ -490,7 +481,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
490481 // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
491482 ty @ Type :: Path ( ..) if type_matches_path ( ty, & [ "rustc_span" , "Span" ] ) => {
492483 let binding = & info. binding . binding ;
493- Ok ( ( quote ! ( * #binding) , None ) )
484+ Ok ( ( quote ! ( #binding) , None ) )
494485 }
495486 // If `ty` is `(Span, Applicability)` then return tokens accessing those.
496487 Type :: Tuple ( tup) => {
0 commit comments