From ddf30e6313215c93ecb1b053db8b39df22986cfc Mon Sep 17 00:00:00 2001 From: Adaline Simonian Date: Sun, 19 Jan 2025 23:46:07 -0800 Subject: [PATCH] fix: ambiguous virtual method calls #858 --- .../src/class/data_models/field_var.rs | 1 + godot-macros/src/class/data_models/func.rs | 25 ++++++++++++++++--- .../src/class/data_models/inherent_impl.rs | 2 +- .../class/data_models/interface_trait_impl.rs | 11 ++++++-- godot-macros/src/class/derive_godot_class.rs | 3 ++- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/godot-macros/src/class/data_models/field_var.rs b/godot-macros/src/class/data_models/field_var.rs index a79304dd9..1e95984e7 100644 --- a/godot-macros/src/class/data_models/field_var.rs +++ b/godot-macros/src/class/data_models/field_var.rs @@ -221,6 +221,7 @@ impl GetterSetterImpl { is_script_virtual: false, rpc_info: None, }, + None, ); let export_token = export_token.expect("getter/setter generation should not fail"); diff --git a/godot-macros/src/class/data_models/func.rs b/godot-macros/src/class/data_models/func.rs index 4c1beb7ac..2acfbe5cc 100644 --- a/godot-macros/src/class/data_models/func.rs +++ b/godot-macros/src/class/data_models/func.rs @@ -38,10 +38,12 @@ pub fn make_virtual_callback( class_name: &Ident, signature_info: &SignatureInfo, before_kind: BeforeKind, + interface_trait: Option<&venial::TypeExpr>, ) -> TokenStream { let method_name = &signature_info.method_name; - let wrapped_method = make_forwarding_closure(class_name, signature_info, before_kind); + let wrapped_method = + make_forwarding_closure(class_name, signature_info, before_kind, interface_trait); let sig_tuple = signature_info.tuple_type(); let call_ctx = make_call_context( @@ -75,6 +77,7 @@ pub fn make_virtual_callback( pub fn make_method_registration( class_name: &Ident, func_definition: FuncDefinition, + interface_trait: Option<&venial::TypeExpr>, ) -> ParseResult { let signature_info = &func_definition.signature_info; let sig_tuple = signature_info.tuple_type(); @@ -85,8 +88,12 @@ pub fn make_method_registration( Err(msg) => return bail_fn(msg, &signature_info.method_name), }; - let forwarding_closure = - make_forwarding_closure(class_name, signature_info, BeforeKind::Without); + let forwarding_closure = make_forwarding_closure( + class_name, + signature_info, + BeforeKind::Without, + interface_trait, + ); // String literals let method_name = &signature_info.method_name; @@ -209,6 +216,7 @@ fn make_forwarding_closure( class_name: &Ident, signature_info: &SignatureInfo, before_kind: BeforeKind, + interface_trait: Option<&venial::TypeExpr>, ) -> TokenStream { let method_name = &signature_info.method_name; let params = &signature_info.param_idents; @@ -238,7 +246,16 @@ fn make_forwarding_closure( let method_call = if matches!(before_kind, BeforeKind::OnlyBefore) { TokenStream::new() } else { - quote! { instance.#method_name( #(#params),* ) } + match interface_trait { + Some(interface_trait) => { + let instance_ref = match signature_info.receiver_type { + ReceiverType::Mut => quote! { &mut instance }, + _ => quote! { &instance }, + }; + quote! { <#class_name as #interface_trait>::#method_name( #instance_ref, #(#params),* ) } + } + None => quote! { instance.#method_name( #(#params),* ) }, + } }; quote! { diff --git a/godot-macros/src/class/data_models/inherent_impl.rs b/godot-macros/src/class/data_models/inherent_impl.rs index eff201247..a691426e5 100644 --- a/godot-macros/src/class/data_models/inherent_impl.rs +++ b/godot-macros/src/class/data_models/inherent_impl.rs @@ -98,7 +98,7 @@ pub fn transform_inherent_impl( let method_registrations: Vec = funcs .into_iter() - .map(|func_def| make_method_registration(&class_name, func_def)) + .map(|func_def| make_method_registration(&class_name, func_def, None)) .collect::>>()?; let constant_registration = make_constant_registration(consts, &class_name, &class_name_obj)?; diff --git a/godot-macros/src/class/data_models/interface_trait_impl.rs b/godot-macros/src/class/data_models/interface_trait_impl.rs index 131ad3549..124da6bfb 100644 --- a/godot-macros/src/class/data_models/interface_trait_impl.rs +++ b/godot-macros/src/class/data_models/interface_trait_impl.rs @@ -246,6 +246,7 @@ pub fn transform_trait_impl(original_impl: venial::Impl) -> ParseResult ParseResult { hash_constant: TokenStream, signature_info: SignatureInfo, before_kind: BeforeKind, + interface_trait: Option, } impl OverriddenVirtualFn<'_> { @@ -383,8 +386,12 @@ impl OverriddenVirtualFn<'_> { let pattern = method_name_str; // Lazily generate code for the actual work (calling user function). - let method_callback = - make_virtual_callback(class_name, &self.signature_info, self.before_kind); + let method_callback = make_virtual_callback( + class_name, + &self.signature_info, + self.before_kind, + self.interface_trait.as_ref(), + ); quote! { #(#cfg_attrs)* diff --git a/godot-macros/src/class/derive_godot_class.rs b/godot-macros/src/class/derive_godot_class.rs index 3bc98b25e..15f7ec1d2 100644 --- a/godot-macros/src/class/derive_godot_class.rs +++ b/godot-macros/src/class/derive_godot_class.rs @@ -279,7 +279,8 @@ fn make_user_class_impl( let tool_check = util::make_virtual_tool_check(); let signature_info = SignatureInfo::fn_ready(); - let callback = make_virtual_callback(class_name, &signature_info, BeforeKind::OnlyBefore); + let callback = + make_virtual_callback(class_name, &signature_info, BeforeKind::OnlyBefore, None); // See also __virtual_call() codegen. // This doesn't explicitly check if the base class inherits from Node (and thus has `_ready`), but the derive-macro already does