]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Use properly checked implicit interface implementations
authorRico Tzschichholz <ricotz@ubuntu.com>
Fri, 30 Nov 2018 20:26:15 +0000 (21:26 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Wed, 19 Dec 2018 23:51:37 +0000 (00:51 +0100)
Collect implicit interface implementations in AST and avoid doing the same
checks twice.

This caused double vfunc assignments if an implementation is provided while
a method with the same name is available in prerequisite class.

See https://bugzilla.gnome.org/show_bug.cgi?id=536863
and https://bugzilla.gnome.org/show_bug.cgi?id=652098

Fixes https://gitlab.gnome.org/GNOME/vala/issues/548

codegen/valagtypemodule.vala
tests/Makefile.am
tests/objects/classes-implicit-implementation.vala [new file with mode: 0644]
tests/objects/classes-interfaces.vala [new file with mode: 0644]
vala/valaclass.vala

index bb971c1c499d16d43a9ea8cf4d0c710e80450fe8..3dd0f2c48dc0a5d0bb823e84fd39a24083bce228 100644 (file)
@@ -1472,32 +1472,18 @@ public class Vala.GTypeModule : GErrorModule {
                }
 
                // connect inherited implementations
-               foreach (Method m in iface.get_methods ()) {
-                       if (m.is_abstract) {
-                               Method cl_method = null;
-                               var base_class = cl;
-                               while (base_class != null && cl_method == null) {
-                                       cl_method = base_class.scope.lookup (m.name) as Method;
-                                       base_class = base_class.base_class;
-                               }
-                               if (base_class != null && cl_method.parent_symbol != cl) {
-                                       // method inherited from base class
-
-                                       var base_method = cl_method;
-                                       if (cl_method.base_interface_method != null) {
-                                               base_method = cl_method.base_interface_method;
-                                       } else if (cl_method.base_method != null) {
-                                               //FIXME should this ever be possible here?
-                                               base_method = cl_method.base_method;
-                                       }
+               var it = cl.get_implicit_implementations ().map_iterator ();
+               while (it.next ()) {
+                       Method m = it.get_key ();
+                       if (m.parent_symbol == iface) {
+                               Method base_method = it.get_value ();
 
-                                       generate_method_declaration (base_method, cfile);
+                               generate_method_declaration (base_method, cfile);
 
-                                       CCodeExpression cfunc = new CCodeIdentifier (get_ccode_name (base_method));
-                                       cfunc = cast_method_pointer (base_method, cfunc, iface);
-                                       var ciface = new CCodeIdentifier ("iface");
-                                       ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_vfunc_name (m)), cfunc);
-                               }
+                               CCodeExpression cfunc = new CCodeIdentifier (get_ccode_name (base_method));
+                               cfunc = cast_method_pointer (m, cfunc, iface);
+                               var ciface = new CCodeIdentifier ("iface");
+                               ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_vfunc_name (m)), cfunc);
                        }
                }
 
index f62e5f2c30b74afcb2fc3344eec205ba64b4e2f1..a62998b1b61440109802960f6447d9543181e2bf 100644 (file)
@@ -254,6 +254,8 @@ TESTS = \
        objects/chainup.vala \
        objects/class_only.vala \
        objects/classes.vala \
+       objects/classes-interfaces.vala \
+       objects/classes-implicit-implementation.vala \
        objects/compact-class.vala \
        objects/compact-class-destructor.vala \
        objects/constructor-variadic.test \
diff --git a/tests/objects/classes-implicit-implementation.vala b/tests/objects/classes-implicit-implementation.vala
new file mode 100644 (file)
index 0000000..3931b34
--- /dev/null
@@ -0,0 +1,36 @@
+interface IFoo : Object {
+       public abstract int foo ();
+}
+
+interface IBar : Object {
+}
+
+class Bar : Object {
+       public int foo () {
+               assert_not_reached ();
+               return -1;
+       }
+}
+
+class Baz : Object {
+       public int foo () {
+               return 23;
+       }
+}
+
+class Foo : Bar, IFoo {
+       public int foo () {
+               return 42;
+       }
+}
+
+class Faz : Baz, IFoo, IBar {
+}
+
+void main () {
+       var foo = new Foo ();
+       assert (foo.foo () == 42);
+
+       var baz = new Baz ();
+       assert (baz.foo () == 23);
+}
diff --git a/tests/objects/classes-interfaces.vala b/tests/objects/classes-interfaces.vala
new file mode 100644 (file)
index 0000000..9f24746
--- /dev/null
@@ -0,0 +1,27 @@
+class Base : Object {
+       public void foo () {
+       }
+}
+
+interface IFoo : Base {
+       public abstract string foo ();
+}
+
+interface IBar : Base {
+       public abstract int foo ();
+}
+
+class Manam : Base, IFoo, IBar {
+       public int IBar.foo () {
+               return 23;
+       }
+       public string IFoo.foo () {
+               return "foo";
+       }
+}
+
+void main () {
+       var manam = new Manam ();
+       assert (((IFoo) manam).foo () == "foo");
+       assert (((IBar) manam).foo () == 23);
+}
index 81bc6ba91c4ddc4431702e1d124a2065fa8a366f..419e72d93baca7c26bf209bded02a42fc5905771 100644 (file)
@@ -110,6 +110,7 @@ public class Vala.Class : ObjectTypeSymbol {
        private bool? _is_singleton;
 
        private List<DataType> base_types = new ArrayList<DataType> ();
+       private HashMap<Method,Method> implicit_implementations = new HashMap<Method,Method> ();
 
        /**
         * Specifies the default construction method.
@@ -305,6 +306,10 @@ public class Vala.Class : ObjectTypeSymbol {
                }
        }
 
+       public HashMap<Method,Method> get_implicit_implementations () {
+               return implicit_implementations;
+       }
+
        /**
         * Adds the specified property as a member to this class.
         *
@@ -748,6 +753,9 @@ public class Vala.Class : ObjectTypeSymbol {
                                                                                impl.version.check (source_reference);
                                                                                impl.used = true;
                                                                                implemented = true;
+                                                                               if (impl.base_interface_method == null) {
+                                                                                       implicit_implementations.set (m, impl);
+                                                                               }
                                                                                break;
                                                                        }
                                                                }