summaryrefslogtreecommitdiff
path: root/vala
diff options
context:
space:
mode:
authorLuca Bruno <lucabru@src.gnome.org>2011-06-08 14:10:55 +0200
committerLuca Bruno <lucabru@src.gnome.org>2014-05-18 20:10:22 +0200
commite1a3ff9470763e7c6ff5a887036390bd418f4e46 (patch)
tree46b56f252bdbc74494d5b55b4ad6a318ad173648 /vala
parent911acf52f052a3847af0df5f81688edc9fc2b1b9 (diff)
downloadvala-e1a3ff9470763e7c6ff5a887036390bd418f4e46.tar.gz
Support explicit interface methods implementation
Fixes bug 652098
Diffstat (limited to 'vala')
-rw-r--r--vala/valaclass.vala29
-rw-r--r--vala/valamethod.vala63
-rw-r--r--vala/valaparser.vala7
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) {