diff options
author | Luca Bruno <lucabru@src.gnome.org> | 2011-06-08 14:10:55 +0200 |
---|---|---|
committer | Luca Bruno <lucabru@src.gnome.org> | 2014-05-18 20:10:22 +0200 |
commit | e1a3ff9470763e7c6ff5a887036390bd418f4e46 (patch) | |
tree | 46b56f252bdbc74494d5b55b4ad6a318ad173648 /vala | |
parent | 911acf52f052a3847af0df5f81688edc9fc2b1b9 (diff) | |
download | vala-e1a3ff9470763e7c6ff5a887036390bd418f4e46.tar.gz |
Support explicit interface methods implementation
Fixes bug 652098
Diffstat (limited to 'vala')
-rw-r--r-- | vala/valaclass.vala | 29 | ||||
-rw-r--r-- | vala/valamethod.vala | 63 | ||||
-rw-r--r-- | vala/valaparser.vala | 7 |
3 files changed, 83 insertions, 16 deletions
diff --git a/vala/valaclass.vala b/vala/valaclass.vala index ba23a508f..12a82afd0 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.name == m.name && (impl.base_interface_type == null || impl.base_interface_type.data_type == iface)) { + // 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 3e9096a7d..afc705387 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 3a478bc0c..c465a8e62 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) { |