Better macro errors for get_struct_fields (#17639)
# Objective - Currently, the error span for `get_struct_field` when encountering an enum or union points to the macro invocation, rather than the `enum` or `union` token. It also doesn't mention which macro reported the error. ## Solution - Report the correct error span - Add parameter for passing in the name of the macro invocation ## Testing Bevy compiles fine with this change ## Migration Guide ```rs // before let fields = get_struct_fields(&ast.data); // after let fields = get_struct_fields(&ast.data, "derive(Bundle)"); ``` --------- Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
This commit is contained in:
parent
f33074116b
commit
fb2d79ad60
@ -34,7 +34,7 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
let ecs_path = bevy_ecs_path();
|
||||
|
||||
let named_fields = match get_struct_fields(&ast.data) {
|
||||
let named_fields = match get_struct_fields(&ast.data, "derive(Bundle)") {
|
||||
Ok(fields) => fields,
|
||||
Err(e) => return e.into_compile_error().into(),
|
||||
};
|
||||
@ -191,12 +191,14 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
||||
pub fn derive_map_entities(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
let ecs_path = bevy_ecs_path();
|
||||
|
||||
let map_entities_impl = map_entities(
|
||||
&ast.data,
|
||||
Ident::new("self", Span::call_site()),
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
let struct_name = &ast.ident;
|
||||
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
|
||||
TokenStream::from(quote! {
|
||||
|
@ -1,24 +1,29 @@
|
||||
use proc_macro::Span;
|
||||
use syn::{punctuated::Punctuated, token::Comma, Data, DataStruct, Error, Field, Fields};
|
||||
use syn::{
|
||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataEnum, DataUnion, Error,
|
||||
Field, Fields,
|
||||
};
|
||||
|
||||
/// Get the fields of a data structure if that structure is a struct with named fields;
|
||||
/// otherwise, return a compile error that points to the site of the macro invocation.
|
||||
pub fn get_struct_fields(data: &Data) -> syn::Result<&Punctuated<Field, Comma>> {
|
||||
///
|
||||
/// `meta` should be the name of the macro calling this function.
|
||||
pub fn get_struct_fields<'a>(
|
||||
data: &'a Data,
|
||||
meta: &str,
|
||||
) -> syn::Result<&'a Punctuated<Field, Comma>> {
|
||||
match data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(fields),
|
||||
..
|
||||
}) => Ok(&fields.named),
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Unnamed(fields),
|
||||
..
|
||||
}) => Ok(&fields.unnamed),
|
||||
_ => Err(Error::new(
|
||||
// This deliberately points to the call site rather than the structure
|
||||
// body; marking the entire body as the source of the error makes it
|
||||
// impossible to figure out which `derive` has a problem.
|
||||
Span::call_site().into(),
|
||||
"Only structs are supported",
|
||||
Data::Struct(data_struct) => match &data_struct.fields {
|
||||
Fields::Named(fields_named) => Ok(&fields_named.named),
|
||||
Fields::Unnamed(fields_unnamed) => Ok(&fields_unnamed.unnamed),
|
||||
Fields::Unit => Ok(const { &Punctuated::new() }),
|
||||
},
|
||||
Data::Enum(DataEnum { enum_token, .. }) => Err(Error::new(
|
||||
enum_token.span(),
|
||||
format!("#[{meta}] only supports structs, not enums"),
|
||||
)),
|
||||
Data::Union(DataUnion { union_token, .. }) => Err(Error::new(
|
||||
union_token.span(),
|
||||
format!("#[{meta}] only supports structs, not unions"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user