} 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;
}
methods/bug646345.vala \
methods/bug648320.vala \
methods/bug649562.vala \
+ methods/bug652098.vala \
methods/bug653391.vala \
methods/bug653908.vala \
methods/bug663210.vala \
--- /dev/null
+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
}
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);
+ }
}
/**
/* 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 ()));
}
return _base_method;
}
}
-
+
/**
* Specifies the abstract interface method this method implements.
*/
}
}
+ /**
+ * 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; }
/**
private weak Method _base_method;
private weak Method _base_interface_method;
+ private DataType _base_interface_type;
private bool base_methods_valid;
Method? callback_method;
p.accept (visitor);
}
+ if (base_interface_type != null) {
+ base_interface_type.accept (visitor);
+ }
+
if (return_type != null) {
return_type.accept (visitor);
}
}
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;
}
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;
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) {
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;
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) {