Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disambiguate virtual method calls #1020

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions godot-macros/src/class/data_models/field_var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
30 changes: 26 additions & 4 deletions godot-macros/src/class/data_models/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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<TokenStream> {
let signature_info = &func_definition.signature_info;
let sig_tuple = signature_info.tuple_type();
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -238,7 +246,21 @@ fn make_forwarding_closure(
let method_call = if matches!(before_kind, BeforeKind::OnlyBefore) {
TokenStream::new()
} else {
quote! { instance.#method_name( #(#params),* ) }
match interface_trait {
// impl ITrait for Class {...}
Some(interface_trait) => {
let instance_ref = match signature_info.receiver_type {
ReceiverType::Ref => quote! { &instance },
ReceiverType::Mut => quote! { &mut instance },
_ => unreachable!("unexpected receiver type"), // checked above.
};

quote! { <#class_name as #interface_trait>::#method_name( #instance_ref, #(#params),* ) }
}

// impl Class {...}
None => quote! { instance.#method_name( #(#params),* ) },
}
};

quote! {
Expand Down
2 changes: 1 addition & 1 deletion godot-macros/src/class/data_models/inherent_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub fn transform_inherent_impl(

let method_registrations: Vec<TokenStream> = 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::<ParseResult<Vec<TokenStream>>>()?;

let constant_registration = make_constant_registration(consts, &class_name, &class_name_obj)?;
Expand Down
11 changes: 9 additions & 2 deletions godot-macros/src/class/data_models/interface_trait_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ pub fn transform_trait_impl(original_impl: venial::Impl) -> ParseResult<TokenStr
hash_constant: quote! { hashes::#method_name_ident },
signature_info,
before_kind,
interface_trait: Some(trait_path.clone()),
});
}
}
Expand All @@ -266,6 +267,7 @@ pub fn transform_trait_impl(original_impl: venial::Impl) -> ParseResult<TokenStr
hash_constant: quote! { ::godot::sys::known_virtual_hashes::Node::ready },
signature_info: SignatureInfo::fn_ready(),
before_kind: BeforeKind::OnlyBefore,
interface_trait: None,
};

overridden_virtuals.push(match_arm);
Expand Down Expand Up @@ -366,6 +368,7 @@ struct OverriddenVirtualFn<'a> {
hash_constant: TokenStream,
signature_info: SignatureInfo,
before_kind: BeforeKind,
interface_trait: Option<venial::TypeExpr>,
}

impl OverriddenVirtualFn<'_> {
Expand All @@ -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)*
Expand Down
3 changes: 2 additions & 1 deletion godot-macros/src/class/derive_godot_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 14 additions & 1 deletion itest/rust/src/engine_tests/codegen_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ macro_rules! make_interface_impl {
Self { base }
}

fn process(&mut self, _: f64) {}
fn exit_tree(&mut self) {}
}
};
}
Expand All @@ -170,3 +170,16 @@ macro_rules! make_user_api {
make_class!(CodegenTest3, Node3D);
make_interface_impl!(CodegenTest3, INode3D);
make_user_api!(CodegenTest3, take_param, i32);

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Regression tests for ambiguous method calls: https://github.com/godot-rust/gdext/issues/858
// Also references the above macro-generated class.

#[allow(dead_code)]
trait TraitA {
fn exit_tree(&mut self);
}

impl TraitA for CodegenTest3 {
fn exit_tree(&mut self) {}
}
Loading