[vala/staging] Support explicit interface methods implementation



commit cbaad0815def204737c326060036c890ea9ed53b
Author: Luca Bruno <lucabru src gnome org>
Date:   Wed Jun 8 14:10:55 2011 +0200

    Support explicit interface methods implementation
    
    Fixes bug 652098.

 codegen/valaccodeattribute.vala |    8 ++++-
 tests/Makefile.am               |    1 +
 tests/methods/bug652098.vala    |   43 ++++++++++++++++++++++++++
 vala/valaclass.vala             |   29 ++++++++++++------
 vala/valamethod.vala            |   63 ++++++++++++++++++++++++++++++++++++--
 vala/valaparser.vala            |    7 +++-
 6 files changed, 134 insertions(+), 17 deletions(-)
---
diff --git a/codegen/valaccodeattribute.vala b/codegen/valaccodeattribute.vala
index 7e1c38a..03ace0b 100644
--- a/codegen/valaccodeattribute.vala
+++ b/codegen/valaccodeattribute.vala
@@ -1254,7 +1254,13 @@ public class Vala.CCodeAttribute : AttributeCache {
                } else if (sym is Method) {
                        var m = (Method) sym;
                        if (m.base_method != null || m.base_interface_method != null) {
-                               return "%sreal_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix 
(m.parent_symbol), m.name);
+                               if (m.base_interface_type != null) {
+                                       return "%sreal_%s%s".printf 
(CCodeBaseModule.get_ccode_lower_case_prefix (m.parent_symbol),
+                                                                                                
CCodeBaseModule.get_ccode_lower_case_prefix (m.base_interface_type.data_type),
+                                                                                                m.name);
+                               } else {
+                                       return "%sreal_%s".printf 
(CCodeBaseModule.get_ccode_lower_case_prefix (m.parent_symbol), m.name);
+                               }
                        } else {
                                return name;
                        }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4833286..bcf82e1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -54,6 +54,7 @@ TESTS = \
        methods/bug646345.vala \
        methods/bug648320.vala \
        methods/bug649562.vala \
+       methods/bug652098.vala \
        methods/bug653391.vala \
        methods/bug653908.vala \
        methods/bug663210.vala \
diff --git a/tests/methods/bug652098.vala b/tests/methods/bug652098.vala
new file mode 100644
index 0000000..daa8593
--- /dev/null
+++ b/tests/methods/bug652098.vala
@@ -0,0 +1,43 @@
+interface Iface1 : Object {
+       public abstract int foo ();
+}
+
+interface Iface2 : Object {
+       public abstract int foo ();
+}
+
+class Obj1 : Object, Iface1, Iface2 {
+       public int Iface1.foo () {
+               return 1;
+       }
+
+       public int Iface2.foo () {
+               return 2;
+       }
+}
+
+class Obj2 : Object, Iface1, Iface2 {
+       public int Iface1.foo () {
+               return 1;
+       }
+
+       public int foo () {
+               return 2;
+       }
+}
+
+void main () {
+       var obj1 = new Obj1 ();
+       var iface1 = (Iface1) obj1;
+       var iface2 = (Iface2) obj1;
+       
+       assert (iface1.foo () == 1);
+       assert (iface2.foo () == 2);
+
+       var obj2 = new Obj2 ();
+       iface1 = (Iface1) obj2;
+       iface2 = (Iface2) obj2;
+       
+       assert (iface1.foo () == 1);
+       assert (iface2.foo () == 2);
+}
\ No newline at end of file
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index ba23a50..ab95f43 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -317,7 +317,12 @@ public class Vala.Class : ObjectTypeSymbol {
                }
 
                methods.add (m);
-               scope.add (m.name, m);
+               if (m.base_interface_type == null) {
+                       scope.add (m.name, m);
+               } else {
+                       // explicit interface method implementation
+                       scope.add (null, m);
+               }
        }
 
        /**
@@ -782,18 +787,22 @@ public class Vala.Class : ObjectTypeSymbol {
                                        /* check methods */
                                        foreach (Method m in iface.get_methods ()) {
                                                if (m.is_abstract) {
-                                                       Symbol sym = null;
+                                                       var implemented = false;
                                                        var base_class = this;
-                                                       while (base_class != null && !(sym is Method)) {
-                                                               sym = base_class.scope.lookup (m.name);
+                                                       while (base_class != null) {
+                                                               foreach (var impl in base_class.get_methods 
()) {
+                                                                       if (impl.base_interface_method == m) {
+                                                                               // method is used as 
interface implementation, so it is not unused
+                                                                               impl.check_deprecated 
(source_reference);
+                                                                               impl.check_experimental 
(source_reference);
+                                                                               impl.used = true;
+                                                                               implemented = true;
+                                                                               break;
+                                                                       }
+                                                               }
                                                                base_class = base_class.base_class;
                                                        }
-                                                       if (sym is Method) {
-                                                               // method is used as interface 
implementation, so it is not unused
-                                                               sym.check_deprecated (source_reference);
-                                                               sym.check_experimental (source_reference);
-                                                               sym.used = true;
-                                                       } else {
+                                                       if (!implemented) {
                                                                error = true;
                                                                Report.error (source_reference, "`%s' does 
not implement interface method `%s'".printf (get_full_name (), m.get_full_name ()));
                                                        }
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 3e9096a..afc7053 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -109,7 +109,7 @@ public class Vala.Method : Subroutine {
                        return _base_method;
                }
        }
-       
+
        /**
         * Specifies the abstract interface method this method implements.
         */
@@ -120,6 +120,17 @@ public class Vala.Method : Subroutine {
                }
        }
 
+       /**
+        * Specifies the explicit interface containing the method this method implements.
+        */
+       public DataType base_interface_type {
+               get { return _base_interface_type; }
+               set {
+                       _base_interface_type = value;
+                       _base_interface_type.parent_node = this;
+               }
+       }
+
        public bool entry_point { get; private set; }
 
        /**
@@ -181,6 +192,7 @@ public class Vala.Method : Subroutine {
 
        private weak Method _base_method;
        private weak Method _base_interface_method;
+       private DataType _base_interface_type;
        private bool base_methods_valid;
 
        Method? callback_method;
@@ -249,6 +261,10 @@ public class Vala.Method : Subroutine {
                        p.accept (visitor);
                }
 
+               if (base_interface_type != null) {
+                       base_interface_type.accept (visitor);
+               }
+
                if (return_type != null) {
                        return_type.accept (visitor);
                }
@@ -471,6 +487,10 @@ public class Vala.Method : Subroutine {
        }
 
        public override void replace_type (DataType old_type, DataType new_type) {
+               if (base_interface_type == old_type) {
+                       base_interface_type = new_type;
+                       return;
+               }
                if (return_type == old_type) {
                        return_type = new_type;
                        return;
@@ -532,9 +552,12 @@ public class Vala.Method : Subroutine {
        }
 
        private void find_base_interface_method (Class cl) {
-               // FIXME report error if multiple possible base methods are found
                foreach (DataType type in cl.get_base_types ()) {
                        if (type.data_type is Interface) {
+                               if (base_interface_type != null && base_interface_type.data_type != 
type.data_type) {
+                                       continue;
+                               }
+
                                var sym = type.data_type.scope.lookup (name);
                                if (sym is Signal) {
                                        var sig = (Signal) sym;
@@ -543,19 +566,37 @@ public class Vala.Method : Subroutine {
                                if (sym is Method) {
                                        var base_method = (Method) sym;
                                        if (base_method.is_abstract || base_method.is_virtual) {
-                                               string invalid_match;
+                                               if (base_interface_type == null) {
+                                                       // check for existing explicit implementation
+                                                       var has_explicit_implementation = false;
+                                                       foreach (var m in cl.get_methods ()) {
+                                                               if (m.base_interface_type != null && 
base_method == m.base_interface_method) {
+                                                                       has_explicit_implementation = true;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       if (has_explicit_implementation) {
+                                                               continue;
+                                                       }
+                                               }
+                                               
+                                               string invalid_match = null;
                                                if (!compatible (base_method, out invalid_match)) {
                                                        error = true;
                                                        Report.error (source_reference, "overriding method 
`%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), 
invalid_match));
                                                        return;
                                                }
-
+                                               
                                                _base_interface_method = base_method;
                                                return;
                                        }
                                }
                        }
                }
+
+               if (base_interface_type != null) {
+                       Report.error (source_reference, "%s: no suitable interface method found to 
implement".printf (get_full_name ()));
+               }
        }
 
        public override bool check (CodeContext context) {
@@ -716,6 +757,20 @@ public class Vala.Method : Subroutine {
                        return false;
                }
 
+               if (base_interface_type != null && base_interface_method != null && parent_symbol is Class) {
+                       var cl = (Class) parent_symbol;
+                       foreach (var m in cl.get_methods ()) {
+                               if (m != this && m.base_interface_method == base_interface_method) {
+                                       m.checked = true;
+                                       m.error = true;
+                                       error = true;
+                                       Report.error (source_reference, "`%s' already contains an 
implementation for `%s'".printf (cl.get_full_name (), base_interface_method.get_full_name ()));
+                                       Report.notice (m.source_reference, "previous implementation of `%s' 
was here".printf (base_interface_method.get_full_name ()));
+                                       return false;
+                               }
+                       }
+               }
+
                context.analyzer.current_source_file = old_source_file;
                context.analyzer.current_symbol = old_symbol;
 
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 3a478bc..c465a8e 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -2619,9 +2619,12 @@ public class Vala.Parser : CodeVisitor {
                var access = parse_access_modifier ();
                var flags = parse_member_declaration_modifiers ();
                var type = parse_type (true, false);
-               string id = parse_identifier ();
+               var sym = parse_symbol_name ();
                var type_param_list = parse_type_parameter_list ();
-               var method = new Method (id, type, get_src (begin), comment);
+               var method = new Method (sym.name, type, get_src (begin), comment);
+               if (sym.inner != null) {
+                       method.base_interface_type = new UnresolvedType.from_symbol (sym.inner, 
sym.inner.source_reference);
+               }
                method.access = access;
                set_attributes (method, attrs);
                foreach (TypeParameter type_param in type_param_list) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]