@@ -63,33 +63,21 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
63
63
let prv = quote ! { :: godot:: private } ;
64
64
let godot_exports_impl = make_property_impl ( class_name, & fields) ;
65
65
66
- let godot_withbase_impl = if let Some ( Field { name, .. } ) = & fields. base_field {
67
- let implementation = if fields. well_formed_base {
68
- quote ! {
69
- fn to_gd( & self ) -> :: godot:: obj:: Gd <Self > {
70
- self . #name. to_gd( ) . cast( )
66
+ let godot_withbase_impl = if let Some ( Field { name, ty, .. } ) = & fields. base_field {
67
+ // Apply the span of the field's type so that errors show up on the field's type.
68
+ quote_spanned ! { ty. span( ) =>
69
+ impl :: godot:: obj:: WithBaseField for #class_name {
70
+ fn to_gd( & self ) -> :: godot:: obj:: Gd <#class_name> {
71
+ // By not referencing the base field directly here we ensure that the user only gets one error when the base
72
+ // field's type is wrong.
73
+ let base = <#class_name as :: godot:: obj:: WithBaseField >:: base_field( self ) ;
74
+ base. to_gd( ) . cast( )
71
75
}
72
76
73
- fn base_field( & self ) -> & :: godot:: obj:: Base <<Self as :: godot:: obj:: GodotClass >:: Base > {
77
+ fn base_field( & self ) -> & :: godot:: obj:: Base <<#class_name as :: godot:: obj:: GodotClass >:: Base > {
74
78
& self . #name
75
79
}
76
80
}
77
- } else {
78
- quote ! {
79
- fn to_gd( & self ) -> :: godot:: obj:: Gd <Self > {
80
- todo!( )
81
- }
82
-
83
- fn base_field( & self ) -> & :: godot:: obj:: Base <<Self as :: godot:: obj:: GodotClass >:: Base > {
84
- todo!( )
85
- }
86
- }
87
- } ;
88
-
89
- quote ! {
90
- impl :: godot:: obj:: WithBaseField for #class_name {
91
- #implementation
92
- }
93
81
}
94
82
} else {
95
83
TokenStream :: new ( )
@@ -241,14 +229,15 @@ impl ClassAttributes {
241
229
}
242
230
243
231
fn make_godot_init_impl ( class_name : & Ident , fields : & Fields ) -> TokenStream {
244
- let base_init = if let Some ( Field { name, .. } ) = & fields. base_field {
245
- let base = if fields. well_formed_base {
246
- quote ! { base }
247
- } else {
248
- quote ! { :: std:: todo!( "The base field is currently broken" ) }
232
+ let base_init = if let Some ( Field { name, ty, .. } ) = & fields. base_field {
233
+ let base_type =
234
+ quote_spanned ! { ty. span( ) => <#class_name as :: godot:: obj:: GodotClass >:: Base } ;
235
+ let base_field_type = quote_spanned ! { ty. span( ) => :: godot:: obj:: Base <#base_type> } ;
236
+ let base = quote_spanned ! { ty. span( ) =>
237
+ <#base_field_type as :: godot:: obj:: IsBase <#base_type, #ty>>:: conv( base)
249
238
} ;
250
239
251
- quote ! { #name: #base, }
240
+ quote_spanned ! { ty . span ( ) => #name: #base, }
252
241
} else {
253
242
TokenStream :: new ( )
254
243
} ;
@@ -267,9 +256,7 @@ fn make_godot_init_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
267
256
268
257
quote ! {
269
258
impl :: godot:: obj:: cap:: GodotDefault for #class_name {
270
- fn __godot_user_init( base: :: godot:: obj:: Base <Self :: Base >) -> Self {
271
- // If the base field is broken then we may get unreachable code due to the `todo`.
272
- #[ allow( unreachable_code) ]
259
+ fn __godot_user_init( base: :: godot:: obj:: Base <<#class_name as :: godot:: obj:: GodotClass >:: Base >) -> Self {
273
260
Self {
274
261
#( #rest_init ) *
275
262
#base_init
@@ -451,8 +438,6 @@ fn parse_fields(
451
438
let mut base_field = Option :: < Field > :: None ;
452
439
let mut deprecations = vec ! [ ] ;
453
440
let mut errors = vec ! [ ] ;
454
- // Base field is either absent or exists and has no errors.
455
- let mut well_formed_base = true ;
456
441
457
442
// Attributes on struct fields
458
443
for ( named_field, _punct) in named_fields {
@@ -573,39 +558,34 @@ fn parse_fields(
573
558
// Extra validation; eventually assign to base_fields or all_fields.
574
559
if is_base {
575
560
if field. is_onready {
576
- well_formed_base = false ;
577
561
errors. push ( error ! (
578
562
field. ty. clone( ) ,
579
563
"base field cannot have type `OnReady<T>`"
580
564
) ) ;
581
565
}
582
566
583
567
if let Some ( var) = field. var . as_ref ( ) {
584
- well_formed_base = false ;
585
568
errors. push ( error ! (
586
569
var. span,
587
570
"base field cannot have the attribute #[var]"
588
571
) ) ;
589
572
}
590
573
591
574
if let Some ( export) = field. export . as_ref ( ) {
592
- well_formed_base = false ;
593
575
errors. push ( error ! (
594
576
export. span,
595
577
"base field cannot have the attribute #[export]"
596
578
) ) ;
597
579
}
598
580
599
581
if let Some ( default_val) = field. default_val . as_ref ( ) {
600
- well_formed_base = false ;
601
582
errors. push ( error ! (
602
583
default_val. span,
603
584
"base field cannot have the attribute #[init]"
604
585
) ) ;
605
586
}
606
587
607
588
if let Some ( prev_base) = base_field. replace ( field) {
608
- well_formed_base = false ;
609
589
// Ensure at most one Base<T>.
610
590
errors. push ( error ! (
611
591
// base_field.unwrap().name,
@@ -621,7 +601,6 @@ fn parse_fields(
621
601
Ok ( Fields {
622
602
all_fields,
623
603
base_field,
624
- well_formed_base,
625
604
deprecations,
626
605
errors,
627
606
} )
0 commit comments