@@ -229,7 +229,7 @@ pub(crate) enum AttributeOrder {
229
229
KeepLast ,
230
230
}
231
231
232
- type ConvertFn < E > = fn ( ThinVec < E > ) -> AttributeKind ;
232
+ type ConvertFn < E > = fn ( ThinVec < E > , Span ) -> AttributeKind ;
233
233
234
234
/// Alternative to [`AttributeParser`] that automatically handles state management.
235
235
/// If multiple attributes appear on an element, combines the values of each into a
@@ -260,25 +260,40 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
260
260
261
261
/// Use in combination with [`CombineAttributeParser`].
262
262
/// `Combine<T: CombineAttributeParser>` implements [`AttributeParser`].
263
- pub ( crate ) struct Combine < T : CombineAttributeParser < S > , S : Stage > (
264
- PhantomData < ( S , T ) > ,
265
- ThinVec < <T as CombineAttributeParser < S > >:: Item > ,
266
- ) ;
263
+ pub ( crate ) struct Combine < T : CombineAttributeParser < S > , S : Stage > {
264
+ phantom : PhantomData < ( S , T ) > ,
265
+ /// A list of all items produced by parsing attributes so far. One attribute can produce any amount of items.
266
+ items : ThinVec < <T as CombineAttributeParser < S > >:: Item > ,
267
+ /// The full span of the first attribute that was encountered.
268
+ first_span : Option < Span > ,
269
+ }
267
270
268
271
impl < T : CombineAttributeParser < S > , S : Stage > Default for Combine < T , S > {
269
272
fn default ( ) -> Self {
270
- Self ( Default :: default ( ) , Default :: default ( ) )
273
+ Self {
274
+ phantom : Default :: default ( ) ,
275
+ items : Default :: default ( ) ,
276
+ first_span : Default :: default ( ) ,
277
+ }
271
278
}
272
279
}
273
280
274
281
impl < T : CombineAttributeParser < S > , S : Stage > AttributeParser < S > for Combine < T , S > {
275
282
const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
276
283
T :: PATH ,
277
284
<T as CombineAttributeParser < S > >:: TEMPLATE ,
278
- |group : & mut Combine < T , S > , cx, args| group. 1 . extend ( T :: extend ( cx, args) ) ,
285
+ |group : & mut Combine < T , S > , cx, args| {
286
+ // Keep track of the span of the first attribute, for diagnostics
287
+ group. first_span . get_or_insert ( cx. attr_span ) ;
288
+ group. items . extend ( T :: extend ( cx, args) )
289
+ } ,
279
290
) ] ;
280
291
281
292
fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
282
- if self . 1 . is_empty ( ) { None } else { Some ( T :: CONVERT ( self . 1 ) ) }
293
+ if let Some ( first_span) = self . first_span {
294
+ Some ( T :: CONVERT ( self . items , first_span) )
295
+ } else {
296
+ None
297
+ }
283
298
}
284
299
}
0 commit comments