@@ -71,31 +71,46 @@ impl<'a> SessionDiagnosticDerive<'a> {
71
71
}
72
72
} ;
73
73
74
+ // Keep track of which fields are subdiagnostics
75
+ let mut subdiagnostics = std:: collections:: HashSet :: new ( ) ;
76
+
74
77
// Generates calls to `span_label` and similar functions based on the attributes
75
78
// on fields. Code for suggestions uses formatting machinery and the value of
76
79
// other fields - because any given field can be referenced multiple times, it
77
80
// should be accessed through a borrow. When passing fields to `set_arg` (which
78
81
// happens below) for Fluent, we want to move the data, so that has to happen
79
82
// in a separate pass over the fields.
80
- let attrs = structure. each ( |field_binding| {
81
- let field = field_binding. ast ( ) ;
82
- let result = field. attrs . iter ( ) . map ( |attr| {
83
- builder
84
- . generate_field_attr_code (
85
- attr,
86
- FieldInfo {
87
- vis : & field. vis ,
88
- binding : field_binding,
89
- ty : & field. ty ,
90
- span : & field. span ( ) ,
91
- } ,
92
- )
93
- . unwrap_or_else ( |v| v. to_compile_error ( ) )
83
+ let attrs = structure
84
+ . clone ( )
85
+ // Remove the fields that have a `subdiagnostic` attribute.
86
+ . filter ( |field_binding| {
87
+ field_binding. ast ( ) . attrs . iter ( ) . all ( |attr| {
88
+ "subdiagnostic" != attr. path . segments . last ( ) . unwrap ( ) . ident . to_string ( )
89
+ || {
90
+ subdiagnostics. insert ( field_binding. binding . clone ( ) ) ;
91
+ false
92
+ }
93
+ } )
94
+ } )
95
+ . each ( |field_binding| {
96
+ let field = field_binding. ast ( ) ;
97
+ let result = field. attrs . iter ( ) . map ( |attr| {
98
+ builder
99
+ . generate_field_attr_code (
100
+ attr,
101
+ FieldInfo {
102
+ vis : & field. vis ,
103
+ binding : field_binding,
104
+ ty : & field. ty ,
105
+ span : & field. span ( ) ,
106
+ } ,
107
+ )
108
+ . unwrap_or_else ( |v| v. to_compile_error ( ) )
109
+ } ) ;
110
+
111
+ quote ! { #( #result) ; * }
94
112
} ) ;
95
113
96
- quote ! { #( #result) ; * }
97
- } ) ;
98
-
99
114
// When generating `set_arg` calls, move data rather than borrow it to avoid
100
115
// requiring clones - this must therefore be the last use of each field (for
101
116
// example, any formatting machinery that might refer to a field should be
@@ -107,7 +122,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
107
122
// need to be passed as an argument to the diagnostic. But when a field has no
108
123
// attributes then it must be passed as an argument to the diagnostic so that
109
124
// it can be referred to by Fluent messages.
110
- if field. attrs . is_empty ( ) {
125
+ let tokens = if field. attrs . is_empty ( ) {
111
126
let diag = & builder. diag ;
112
127
let ident = field_binding. ast ( ) . ident . as_ref ( ) . unwrap ( ) ;
113
128
quote ! {
@@ -118,6 +133,27 @@ impl<'a> SessionDiagnosticDerive<'a> {
118
133
}
119
134
} else {
120
135
quote ! { }
136
+ } ;
137
+ // If this field had a subdiagnostic attribute, we generate the code here to
138
+ // avoid binding it twice.
139
+ if subdiagnostics. contains ( & field_binding. binding ) {
140
+ let result = field. attrs . iter ( ) . map ( |attr| {
141
+ builder
142
+ . generate_field_attr_code (
143
+ attr,
144
+ FieldInfo {
145
+ vis : & field. vis ,
146
+ binding : field_binding,
147
+ ty : & field. ty ,
148
+ span : & field. span ( ) ,
149
+ } ,
150
+ )
151
+ . unwrap_or_else ( |v| v. to_compile_error ( ) )
152
+ } ) ;
153
+
154
+ quote ! { #( #result) ; * #tokens }
155
+ } else {
156
+ tokens
121
157
}
122
158
} ) ;
123
159
@@ -359,6 +395,8 @@ impl SessionDiagnosticDeriveBuilder {
359
395
let ( binding, needs_destructure) = match ( name. as_str ( ) , & inner_ty) {
360
396
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
361
397
( "primary_span" , FieldInnerTy :: Vec ( _) ) => ( quote ! { #field_binding. clone( ) } , false ) ,
398
+ // `subdiagnostics` are not derefed because they are bound by value.
399
+ ( "subdiagnostic" , _) => ( quote ! { #field_binding } , true ) ,
362
400
_ => ( quote ! { * #field_binding } , true ) ,
363
401
} ;
364
402
0 commit comments