[vala] Support explicit interface methods implementation
- From: Luca Bruno <lucabru src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala] Support explicit interface methods implementation
- Date: Sun, 18 May 2014 18:10:44 +0000 (UTC)
commit e1a3ff9470763e7c6ff5a887036390bd418f4e46
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 | 55 ++++++++++++++++++++++++++++++++++
vala/valaclass.vala | 29 ++++++++++++------
vala/valamethod.vala | 63 ++++++++++++++++++++++++++++++++++++--
vala/valaparser.vala | 7 +++-
6 files changed, 146 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..d16f27f
--- /dev/null
+++ b/tests/methods/bug652098.vala
@@ -0,0 +1,55 @@
+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;
+ }
+}
+
+class Base : Object {
+ public void foo () {
+ }
+}
+
+interface Iface : Object {
+ public abstract void foo ();
+}
+
+class Concrete : Base, Iface {
+}
+
+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..12a82af 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 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]