]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Use G_TYPE_INSTANCE_GET_INTERFACE to get vtable for base-access
authorRico Tzschichholz <ricotz@ubuntu.com>
Thu, 17 Oct 2019 12:04:15 +0000 (14:04 +0200)
committerRico Tzschichholz <ricotz@ubuntu.com>
Thu, 7 Nov 2019 10:52:44 +0000 (11:52 +0100)
Usage of the pre-assigned *_parent_iface field is only possible in classes
which explicitly implement an interface.

codegen/valaccodebasemodule.vala
codegen/valaccodememberaccessmodule.vala
codegen/valaccodemethodcallmodule.vala
tests/Makefile.am
tests/objects/interface-async-base-access.vala [new file with mode: 0644]
tests/objects/interface-base-access.vala [new file with mode: 0644]
tests/objects/interface-property-base-access.vala [new file with mode: 0644]
vala/valaclass.vala

index 7ae022aa331dc22db432d87079da95ea8bc08696..c9362387ed4aa54ee69330db3d7a47630a0f8ae9 100644 (file)
@@ -2391,6 +2391,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));
        }
@@ -6185,9 +6201,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 ()) {
index 8fb01eaa6fab14f937470ee28232dc3dee834405..2359f4ba80eeb12f5f1e04533067fa71a5e86c34 100644 (file)
@@ -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;
                                }
                        }
@@ -206,9 +206,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);
index d388e15b812a8a57f24bd6922db51492bcd64d8c..3a698d61211f56829511934d268b69d0238f63c5 100644 (file)
@@ -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));
                                }
                        }
 
index 357ba69246410ba58817a88f00889732bb04d2d5..b6ed4f9310a5fa94956c4670d4456d694f220b87 100644 (file)
@@ -314,8 +314,11 @@ TESTS = \
        objects/gsource.vala \
        objects/instance-comparison.vala \
        objects/interface_only.vala \
+       objects/interface-async-base-access.vala \
+       objects/interface-base-access.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 (file)
index 0000000..2c8bccf
--- /dev/null
@@ -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 (file)
index 0000000..f0e853e
--- /dev/null
@@ -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 (file)
index 0000000..036ce8b
--- /dev/null
@@ -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");
+}
index 51e8fbade672c685e592020da05bd07e53dc54eb..9823d76a39d3c0b345251e6b4fe64a523c346aa1 100644 (file)
@@ -497,14 +497,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.data_type is Class) {
-                               if (class_is_a ((Class) base_type.data_type, t)) {
+                               if (((Class) base_type.data_type).is_a (t)) {
                                        return true;
                                }
                        } else if (base_type.data_type == t) {
@@ -515,6 +515,16 @@ public class Vala.Class : ObjectTypeSymbol {
                return false;
        }
 
+       public bool implements (Interface i) {
+               foreach (DataType base_type in get_base_types ()) {
+                       if (base_type.data_type == i) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
        public override bool check (CodeContext context) {
                if (checked) {
                        return !error;
@@ -695,7 +705,7 @@ public class Vala.Class : ObjectTypeSymbol {
                /* check whether all prerequisites are met */
                List<string> missing_prereqs = new ArrayList<string> ();
                foreach (TypeSymbol prereq in prerequisites) {
-                       if (!class_is_a (this, prereq)) {
+                       if (!is_a ((ObjectTypeSymbol) prereq)) {
                                missing_prereqs.insert (0, prereq.get_full_name ());
                        }
                }