Skip to content

Commit ae0769d

Browse files
committed
use spanned errors instead of panics
1 parent cc895ee commit ae0769d

File tree

1 file changed

+34
-11
lines changed
  • crates/bevy_macro_utils/src

1 file changed

+34
-11
lines changed

crates/bevy_macro_utils/src/lib.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ pub use shape::*;
99
pub use symbol::*;
1010

1111
use proc_macro::TokenStream;
12-
use quote::quote;
12+
use quote::{quote, quote_spanned};
1313
use std::{env, path::PathBuf};
14+
use syn::spanned::Spanned;
1415
use toml::{map::Map, Value};
1516

1617
pub struct BevyManifest {
@@ -125,7 +126,7 @@ pub fn derive_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStr
125126
.unwrap()
126127
}
127128

128-
let ident = input.ident;
129+
let ident = input.ident.clone();
129130

130131
use convert_case::{Case, Casing};
131132
let trait_snake_case = trait_path
@@ -145,28 +146,42 @@ pub fn derive_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStr
145146
.predicates
146147
.push(syn::parse2(quote! { Self: 'static }).unwrap());
147148

148-
let ignore_fields = input.attrs.iter().any(|a| is_ignore(a, &trait_snake_case));
149149
let as_str = match input.data {
150150
syn::Data::Struct(d) => {
151151
// see if the user tried to ignore fields incorrectly
152-
if d.fields
152+
if let Some(attr) = d
153+
.fields
153154
.iter()
154155
.flat_map(|f| &f.attrs)
155-
.any(|a| is_ignore(a, &trait_snake_case))
156+
.find(|a| is_ignore(a, &trait_snake_case))
156157
{
157-
panic!("`#[{trait_snake_case}(ignore_fields)]` cannot be applied to fields individually: add it to the struct declaration");
158+
let err_msg = format!("`#[{trait_snake_case}(ignore_fields)]` cannot be applied to fields individually: add it to the struct declaration");
159+
return quote_spanned! {
160+
attr.span() => compile_error!(#err_msg);
161+
}
162+
.into();
158163
}
159164
// Structs must either be fieldless, or explicitly ignore the fields.
165+
let ignore_fields = input.attrs.iter().any(|a| is_ignore(a, &trait_snake_case));
160166
if matches!(d.fields, syn::Fields::Unit) || ignore_fields {
161167
let lit = ident.to_string();
162168
quote! { #lit }
163169
} else {
164-
panic!("Labels cannot contain data, unless explicitly ignored with `#[{trait_snake_case}(ignore_fields)]`");
170+
let err_msg = format!("Labels cannot contain data, unless explicitly ignored with `#[{trait_snake_case}(ignore_fields)]`");
171+
return quote_spanned! {
172+
d.fields.span() => compile_error!(#err_msg);
173+
}
174+
.into();
165175
}
166176
}
167177
syn::Data::Enum(d) => {
168-
if ignore_fields {
169-
panic!("`#[{trait_snake_case}(ignore_fields)]` can only be applied to struct declarations or enum variants");
178+
// check if the user put #[label(ignore_fields)] in the wrong place
179+
if let Some(attr) = input.attrs.iter().find(|a| is_ignore(a, &trait_snake_case)) {
180+
let err_msg = format!("`#[{trait_snake_case}(ignore_fields)]` can only be applied to enum variants or struct declarations");
181+
return quote_spanned! {
182+
attr.span() => compile_error!(#err_msg);
183+
}
184+
.into();
170185
}
171186
let arms = d.variants.iter().map(|v| {
172187
// Variants must either be fieldless, or explicitly ignore the fields.
@@ -177,7 +192,10 @@ pub fn derive_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStr
177192
let lit = format!("{ident}::{}", v.ident.clone());
178193
quote! { #path { .. } => #lit }
179194
} else {
180-
panic!("Label variants cannot contain data, unless explicitly ignored with `#[{trait_snake_case}(ignore_fields)]`");
195+
let err_msg = format!("Label variants cannot contain data, unless explicitly ignored with `#[{trait_snake_case}(ignore_fields)]`");
196+
quote_spanned! {
197+
v.fields.span() => _ => { compile_error!(#err_msg); }
198+
}
181199
}
182200
});
183201
quote! {
@@ -186,7 +204,12 @@ pub fn derive_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStr
186204
}
187205
}
188206
}
189-
syn::Data::Union(_) => panic!("Unions cannot be used as labels."),
207+
syn::Data::Union(_) => {
208+
return quote_spanned! {
209+
input.span() => compile_error!("Unions cannot be used as labels.");
210+
}
211+
.into();
212+
}
190213
};
191214

192215
(quote! {

0 commit comments

Comments
 (0)