Skip to content

Commit 02c11b5

Browse files
authored
Merge pull request #773 from fpdotmonkey/better-derive-gd-class-error-messages
Reorder compile errors for `#[derive(GodotClass)]`
2 parents 26ef0dc + 5bb8ff5 commit 02c11b5

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

godot-macros/src/class/derive_godot_class.rs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
2020
.as_struct()
2121
.ok_or_else(|| venial::Error::new("Not a valid struct"))?;
2222

23+
let named_fields = named_fields(class)?;
2324
let struct_cfg = parse_struct_attributes(class)?;
24-
let fields = parse_fields(class, struct_cfg.init_strategy)?;
25+
let fields = parse_fields(named_fields, struct_cfg.init_strategy)?;
2526

2627
let class_name = &class.name;
2728
let class_name_str: String = struct_cfg
@@ -292,9 +293,6 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult<ClassAttribute
292293
base_ty = base;
293294
}
294295

295-
// #[class(rename = NewName)]
296-
rename = parser.handle_ident("rename")?;
297-
298296
// #[class(init)], #[class(no_init)]
299297
match handle_opposite_keys(&mut parser, "init", "class")? {
300298
Some(true) => init_strategy = InitStrategy::Generated,
@@ -314,20 +312,25 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult<ClassAttribute
314312
is_editor_plugin = true;
315313

316314
// Requires #[class(tool, base=EditorPlugin)].
317-
if !is_tool {
315+
// The base=EditorPlugin check should come first to create the best compile errors since it's more complex to resolve.
316+
// See https://github.com/godot-rust/gdext/pull/773
317+
if base_ty != ident("EditorPlugin") {
318318
return bail!(
319319
attr_key,
320-
"#[class(editor_plugin)] requires additional key `tool`"
320+
"#[class(editor_plugin)] requires additional key-value `base=EditorPlugin`"
321321
);
322322
}
323-
if base_ty != ident("EditorPlugin") {
323+
if !is_tool {
324324
return bail!(
325325
attr_key,
326-
"#[class(editor_plugin)] requires additional key-value `base=EditorPlugin`"
326+
"#[class(editor_plugin)] requires additional key `tool`"
327327
);
328328
}
329329
}
330330

331+
// #[class(rename = NewName)]
332+
rename = parser.handle_ident("rename")?;
333+
331334
// #[class(hidden)]
332335
// TODO consider naming this "internal"; godot-cpp uses that terminology:
333336
// https://github.com/godotengine/godot-cpp/blob/master/include/godot_cpp/core/class_db.hpp#L327
@@ -349,22 +352,30 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult<ClassAttribute
349352
})
350353
}
351354

352-
/// Returns field names and 1 base field, if available
353-
fn parse_fields(class: &venial::Struct, init_strategy: InitStrategy) -> ParseResult<Fields> {
354-
let mut all_fields = vec![];
355-
let mut base_field = Option::<Field>::None;
356-
let mut has_deprecated_base = false;
357-
358-
let named_fields: Vec<(venial::NamedField, Punct)> = match &class.fields {
359-
venial::Fields::Unit => {
360-
vec![]
361-
}
355+
/// Fetches data for all named fields for a struct.
356+
///
357+
/// Errors if `class` is a tuple struct.
358+
fn named_fields(class: &venial::Struct) -> ParseResult<Vec<(venial::NamedField, Punct)>> {
359+
// This is separate from parse_fields to improve compile errors. The errors from here demand larger and more non-local changes from the API
360+
// user than those from parse_struct_attributes, so this must be run first.
361+
match &class.fields {
362+
venial::Fields::Unit => Ok(vec![]),
362363
venial::Fields::Tuple(_) => bail!(
363364
&class.fields,
364365
"#[derive(GodotClass)] not supported for tuple structs",
365366
)?,
366-
venial::Fields::Named(fields) => fields.fields.inner.clone(),
367-
};
367+
venial::Fields::Named(fields) => Ok(fields.fields.inner.clone()),
368+
}
369+
}
370+
371+
/// Returns field names and 1 base field, if available.
372+
fn parse_fields(
373+
named_fields: Vec<(venial::NamedField, Punct)>,
374+
init_strategy: InitStrategy,
375+
) -> ParseResult<Fields> {
376+
let mut all_fields = vec![];
377+
let mut base_field = Option::<Field>::None;
378+
let mut has_deprecated_base = false;
368379

369380
// Attributes on struct fields
370381
for (named_field, _punct) in named_fields {

0 commit comments

Comments
 (0)