From 0aace7bd6d3ec72e77f4eabbb7d5fffd3b2e86a8 Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Thu, 17 Oct 2019 14:04:15 +0200 Subject: [PATCH] codegen: Use G_TYPE_INSTANCE_GET_INTERFACE to get vtable for base-access Usage of the pre-assigned *_parent_iface field is only possible in classes which explicitly implement an interface. --- codegen/valaccodebasemodule.vala | 20 +++++++++++++-- codegen/valaccodememberaccessmodule.vala | 8 +++--- codegen/valaccodemethodcallmodule.vala | 6 ++--- tests/Makefile.am | 3 +++ .../objects/interface-async-base-access.vala | 25 +++++++++++++++++++ tests/objects/interface-base-access.vala | 25 +++++++++++++++++++ .../interface-property-base-access.vala | 20 +++++++++++++++ vala/valaclass.vala | 20 +++++++++++---- 8 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 tests/objects/interface-async-base-access.vala create mode 100644 tests/objects/interface-base-access.vala create mode 100644 tests/objects/interface-property-base-access.vala diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 83f028013..7c1c2290c 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -2385,6 +2385,22 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { return get_cexpression ("self"); } + public CCodeExpression get_this_interface_cexpression (Interface iface) { + if (current_class.implements (iface)) { + return new CCodeIdentifier ("%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (iface))); + } + + if (!current_class.is_a (iface)) { + Report.warning (current_class.source_reference, "internal: `%s' is not a `%s'".printf (current_class.get_full_name (), iface.get_full_name ())); + } + + var vcast = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE")); + vcast.add_argument (get_this_cexpression ()); + vcast.add_argument (new CCodeIdentifier (get_ccode_type_id (iface))); + vcast.add_argument (new CCodeIdentifier (get_ccode_type_name (iface))); + return vcast; + } + public CCodeExpression get_inner_error_cexpression () { return get_cexpression ("_inner_error%d_".printf (current_inner_error_id)); } @@ -6039,9 +6055,9 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { ccode.add_expression (ccall); } else if (prop.base_interface_property != null) { var base_iface = (Interface) prop.base_interface_property.parent_symbol; - string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface)); + var vcast = get_this_interface_cexpression (base_iface); - var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name))); + var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name))); ccall.add_argument ((CCodeExpression) get_ccodenode (instance)); var cexpr = get_cvalue_ (value); if (prop.property_type.is_real_non_null_struct_type ()) { diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala index 54a71a3e2..2a37ceb5c 100644 --- a/codegen/valaccodememberaccessmodule.vala +++ b/codegen/valaccodememberaccessmodule.vala @@ -58,9 +58,9 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule { return; } else if (m.base_interface_method != null) { var base_iface = (Interface) m.base_interface_method.parent_symbol; - string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface)); + var vcast = get_this_interface_cexpression (base_iface); - set_cvalue (expr, new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), get_ccode_vfunc_name (m))); + set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m))); return; } } @@ -219,9 +219,9 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule { } } else if (base_prop.parent_symbol is Interface) { var base_iface = (Interface) base_prop.parent_symbol; - string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface)); + var vcast = get_this_interface_cexpression (base_iface); - var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "get_%s".printf (prop.name))); + var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name))); ccall.add_argument (get_cvalue (expr.inner)); if (prop.property_type.is_real_non_null_struct_type ()) { var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr); diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index 3c3290092..fc0561dd7 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -104,10 +104,10 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m)); } else if (m.base_interface_method != null) { var base_iface = (Interface) m.base_interface_method.parent_symbol; - string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface)); + var vcast = get_this_interface_cexpression (base_iface); - async_call.call = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), get_ccode_vfunc_name (m)); - finish_call.call = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), get_ccode_finish_vfunc_name (m)); + async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)); + finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m)); } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 6578f43ab..b0a89eb41 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -323,9 +323,12 @@ TESTS = \ objects/gsource.vala \ objects/instance-comparison.vala \ objects/interface_only.vala \ + objects/interface-async-base-access.vala + objects/interface-base-access.vala objects/interface-inner-types.vala \ objects/interfaces.vala \ objects/interface-generics.vala \ + objects/interface-property-base-access.vala objects/interface-virtual-override.vala \ objects/methods.vala \ objects/paramspec.vala \ diff --git a/tests/objects/interface-async-base-access.vala b/tests/objects/interface-async-base-access.vala new file mode 100644 index 000000000..2c8bccfd9 --- /dev/null +++ b/tests/objects/interface-async-base-access.vala @@ -0,0 +1,25 @@ +interface IFoo { + public abstract async void foo (); +} + +class Bar : IFoo { + public async void foo () { + reached = true; + } +} + +class Foo : Bar { + public async void bar () { + yield base.foo (); + } +} + +bool reached = false; + +void main () { + var foo = new Foo (); + assert (foo is IFoo); + + foo.bar.begin (); + assert (reached); +} diff --git a/tests/objects/interface-base-access.vala b/tests/objects/interface-base-access.vala new file mode 100644 index 000000000..f0e853e25 --- /dev/null +++ b/tests/objects/interface-base-access.vala @@ -0,0 +1,25 @@ +interface IFoo { + public abstract void foo (); +} + +class Bar : IFoo { + public void foo () { + reached = true; + } +} + +class Foo : Bar { + public void bar () { + base.foo (); + } +} + +bool reached = false; + +void main () { + var foo = new Foo (); + assert (foo is IFoo); + + foo.bar (); + assert (reached); +} diff --git a/tests/objects/interface-property-base-access.vala b/tests/objects/interface-property-base-access.vala new file mode 100644 index 000000000..036ce8b1e --- /dev/null +++ b/tests/objects/interface-property-base-access.vala @@ -0,0 +1,20 @@ +interface IFoo { + public abstract string foo { get; set; } +} + +class Bar : IFoo { + public string foo { get; set; } +} + +class Foo : Bar { + public string bar (string s) { + base.foo = s; + return base.foo; + } +} + +void main () { + var foo = new Foo (); + assert (foo is IFoo); + assert (foo.bar ("foo") == "foo"); +} diff --git a/vala/valaclass.vala b/vala/valaclass.vala index 507a10d23..6cad8e00a 100644 --- a/vala/valaclass.vala +++ b/vala/valaclass.vala @@ -469,14 +469,14 @@ public class Vala.Class : ObjectTypeSymbol { } } - private bool class_is_a (Class cl, TypeSymbol t) { - if (cl == t) { + public bool is_a (ObjectTypeSymbol t) { + if (this == t) { return true; } - foreach (DataType base_type in cl.get_base_types ()) { + foreach (DataType base_type in get_base_types ()) { if (base_type.type_symbol is Class) { - if (class_is_a ((Class) base_type.type_symbol, t)) { + if (((Class) base_type.type_symbol).is_a (t)) { return true; } } else if (base_type.type_symbol == t) { @@ -487,6 +487,16 @@ public class Vala.Class : ObjectTypeSymbol { return false; } + public bool implements (Interface i) { + foreach (DataType base_type in get_base_types ()) { + if (base_type.type_symbol == i) { + return true; + } + } + + return false; + } + public override bool check (CodeContext context) { if (checked) { return !error; @@ -671,7 +681,7 @@ public class Vala.Class : ObjectTypeSymbol { /* check whether all prerequisites are met */ List missing_prereqs = new ArrayList (); foreach (TypeSymbol prereq in prerequisites) { - if (!class_is_a (this, prereq)) { + if (!is_a ((ObjectTypeSymbol) prereq)) { missing_prereqs.insert (0, prereq.get_full_name ()); } } -- 2.47.2