]> 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, 17 Oct 2019 20:06:36 +0000 (22:06 +0200)
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 83f028013ed796a95ce2fe61f2ee31255db4c9ed..7c1c2290c073ac1d5a14eef02b934fca4974b943 100644 (file)
@@ -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 ()) {
index 54a71a3e2bfca726f505a31f5a2ac38a9350616d..2a37ceb5c63dc807c92ba969c465a4b9d5cb5da2 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;
                                }
                        }
@@ -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);
index 3c3290092852efa1b5ec397b9ca0633d133d823c..fc0561dd7c3210128695723448b5624c2f1c264f 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 6578f43ab058a1049744746e447b81543353ed93..b0a89eb414b4f42a1a39b18db178d2d04c0c59ab 100644 (file)
@@ -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 (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 507a10d2384766846524549575c6781b32669109..6cad8e00a2f7288655f8794138ea938c4ad3ec67 100644 (file)
@@ -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<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 ());
                        }
                }