mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
bevy_ecs: Replace panics in QueryData
derive compile errors (#15691)
# Objective The current `QueryData` derive panics when it encounters an error. Additionally, it doesn't provide the clearest error message: ```rust #[derive(QueryData)] #[query_data(mut)] struct Foo { // ... } ``` ``` error: proc-macro derive panicked --> src/foo.rs:16:10 | 16 | #[derive(QueryData)] | ^^^^^^^^^ | = help: message: Invalid `query_data` attribute format ``` ## Solution Updated the derive logic to not panic and gave a bit more detail in the error message. This is makes the error message just a bit clearer and maintains the correct span: ``` error: invalid attribute, expected `mutable` or `derive` --> src/foo.rs:17:14 | 17 | #[query_data(mut)] | ^^^ ``` ## Testing You can test locally by running the following in `crates/bevy_ecs/compile_fail`: ``` cargo test --target-dir ../../../target ```
This commit is contained in:
parent
d1927736de
commit
8039f34b0d
2 changed files with 44 additions and 42 deletions
|
@ -10,6 +10,27 @@ struct MutableUnmarked {
|
||||||
a: &'static mut Foo,
|
a: &'static mut Foo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(QueryData)]
|
||||||
|
#[query_data(mut)]
|
||||||
|
//~^ ERROR: invalid attribute, expected `mutable` or `derive`
|
||||||
|
struct MutableInvalidAttribute {
|
||||||
|
a: &'static mut Foo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(QueryData)]
|
||||||
|
#[query_data(mutable(foo))]
|
||||||
|
//~^ ERROR: `mutable` does not take any arguments
|
||||||
|
struct MutableInvalidAttributeParameters {
|
||||||
|
a: &'static mut Foo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(QueryData)]
|
||||||
|
#[query_data(derive)]
|
||||||
|
//~^ ERROR: `derive` requires at least one argument
|
||||||
|
struct MutableMissingAttributeParameters {
|
||||||
|
a: &'static mut Foo,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(QueryData)]
|
#[derive(QueryData)]
|
||||||
#[query_data(mutable)]
|
#[query_data(mutable)]
|
||||||
struct MutableMarked {
|
struct MutableMarked {
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
use bevy_macro_utils::ensure_no_collision;
|
use bevy_macro_utils::ensure_no_collision;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span};
|
||||||
use quote::{format_ident, quote, ToTokens};
|
use quote::{format_ident, quote};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse_macro_input, parse_quote, punctuated::Punctuated, token, token::Comma, Attribute, Data,
|
||||||
parse_macro_input, parse_quote,
|
DataStruct, DeriveInput, Field, Index, Meta,
|
||||||
punctuated::Punctuated,
|
|
||||||
token::Comma,
|
|
||||||
Attribute, Data, DataStruct, DeriveInput, Field, Index, Meta,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -47,45 +44,29 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.parse_args_with(|input: ParseStream| {
|
let result = attr.parse_nested_meta(|meta| {
|
||||||
let meta = input.parse_terminated(Meta::parse, Comma)?;
|
if meta.path.is_ident(MUTABLE_ATTRIBUTE_NAME) {
|
||||||
for meta in meta {
|
|
||||||
let ident = meta.path().get_ident().unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized attribute: `{}`",
|
|
||||||
meta.path().to_token_stream()
|
|
||||||
)
|
|
||||||
});
|
|
||||||
if ident == MUTABLE_ATTRIBUTE_NAME {
|
|
||||||
if let Meta::Path(_) = meta {
|
|
||||||
attributes.is_mutable = true;
|
attributes.is_mutable = true;
|
||||||
|
if meta.input.peek(token::Paren) {
|
||||||
|
Err(meta.error(format_args!("`{MUTABLE_ATTRIBUTE_NAME}` does not take any arguments")))
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
Ok(())
|
||||||
"The `{MUTABLE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
} else if meta.path.is_ident(DERIVE_ATTRIBUTE_NAME) {
|
||||||
else if ident == DERIVE_ATTRIBUTE_NAME {
|
meta.parse_nested_meta(|meta| {
|
||||||
if let Meta::List(meta_list) = meta {
|
|
||||||
meta_list.parse_nested_meta(|meta| {
|
|
||||||
attributes.derive_args.push(Meta::Path(meta.path));
|
attributes.derive_args.push(Meta::Path(meta.path));
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
}).map_err(|_| {
|
||||||
} else {
|
meta.error(format_args!("`{DERIVE_ATTRIBUTE_NAME}` requires at least one argument"))
|
||||||
panic!(
|
|
||||||
"Expected a structured list within the `{DERIVE_ATTRIBUTE_NAME}` attribute",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized attribute: `{}`",
|
|
||||||
meta.path().to_token_stream()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|_| panic!("Invalid `{QUERY_DATA_ATTRIBUTE_NAME}` attribute format"));
|
} else {
|
||||||
|
Err(meta.error(format_args!("invalid attribute, expected `{MUTABLE_ATTRIBUTE_NAME}` or `{DERIVE_ATTRIBUTE_NAME}`")))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
return err.to_compile_error().into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = bevy_ecs_path();
|
let path = bevy_ecs_path();
|
||||||
|
|
Loading…
Reference in a new issue