From: Jürg Billeter Date: Mon, 26 Sep 2016 17:07:17 +0000 (+0200) Subject: Fix type parameter check for overriding generic methods X-Git-Tag: 0.35.1~127 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dadf2b48d4da3f1afd95991bec4d4179e231b010;p=thirdparty%2Fvala.git Fix type parameter check for overriding generic methods https://bugzilla.gnome.org/show_bug.cgi?id=771964 Reported-by: Sebastian Reichel --- diff --git a/tests/Makefile.am b/tests/Makefile.am index d4f0fc3c7..4e684a75d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -72,6 +72,7 @@ TESTS = \ methods/bug736235.vala \ methods/bug737222.vala \ methods/bug743877.vala \ + methods/bug771964.vala \ methods/generics.vala \ control-flow/break.vala \ control-flow/expressions-conditional.vala \ diff --git a/tests/methods/bug771964.vala b/tests/methods/bug771964.vala new file mode 100644 index 000000000..f760e1221 --- /dev/null +++ b/tests/methods/bug771964.vala @@ -0,0 +1,15 @@ +public abstract class Foo : Object { + public abstract void test (T parameter); +} + +public class Bar : Foo { + public override void test (T parameter) { + stdout.printf ("Just a test!\n"); + } +} + +int main () { + var obj = new Bar(); + obj.test ("test"); + return 0; +} diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala index d993e3c93..f6d013292 100644 --- a/vala/valaarraytype.vala +++ b/vala/valaarraytype.vala @@ -258,15 +258,15 @@ public class Vala.ArrayType : ReferenceType { return element_type.check (context); } - public override DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) { + public override DataType get_actual_type (DataType? derived_instance_type, List? method_type_arguments, CodeNode node_reference) { ArrayType result = (ArrayType) this.copy (); - if (derived_instance_type == null && method_access == null) { + if (derived_instance_type == null && method_type_arguments == null) { return result; } if (element_type is GenericType || element_type.has_type_arguments ()) { - result.element_type = result.element_type.get_actual_type (derived_instance_type, method_access, node_reference); + result.element_type = result.element_type.get_actual_type (derived_instance_type, method_type_arguments, node_reference); } return result; diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala index 02b4cf13f..2277224fa 100644 --- a/vala/valadatatype.vala +++ b/vala/valadatatype.vala @@ -441,21 +441,21 @@ public abstract class Vala.DataType : CodeNode { return false; } - public virtual DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) { + public virtual DataType get_actual_type (DataType? derived_instance_type, List? method_type_arguments, CodeNode node_reference) { DataType result = this.copy (); - if (derived_instance_type == null && method_access == null) { + if (derived_instance_type == null && method_type_arguments == null) { return result; } if (result is GenericType) { - result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_access, (GenericType) result, node_reference); + result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_type_arguments, (GenericType) result, node_reference); // don't try to resolve type arguments of returned actual type // they can never be resolved and are not related to the instance type } else if (result.type_argument_list != null) { // recursely get actual types for type arguments for (int i = 0; i < result.type_argument_list.size; i++) { - result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, method_access, node_reference); + result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, method_type_arguments, node_reference); } } diff --git a/vala/valamethod.vala b/vala/valamethod.vala index d9aba3e6c..7c883b5cd 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -322,7 +322,25 @@ public class Vala.Method : Subroutine { } } - var actual_base_type = base_method.return_type.get_actual_type (object_type, null, this); + if (this.get_type_parameters ().size < base_method.get_type_parameters ().size) { + invalid_match = "too few type parameters"; + return false; + } else if (this.get_type_parameters ().size > base_method.get_type_parameters ().size) { + invalid_match = "too many type parameters"; + return false; + } + + List method_type_args = null; + if (this.get_type_parameters ().size > 0) { + method_type_args = new ArrayList (); + foreach (TypeParameter type_parameter in this.get_type_parameters ()) { + var type_arg = new GenericType (type_parameter); + type_arg.value_owned = true; + method_type_args.add (type_arg); + } + } + + var actual_base_type = base_method.return_type.get_actual_type (object_type, method_type_args, this); if (!return_type.equals (actual_base_type)) { invalid_match = "incompatible return type"; return false; @@ -348,7 +366,7 @@ public class Vala.Method : Subroutine { return false; } - actual_base_type = base_param.variable_type.get_actual_type (object_type, null, this); + actual_base_type = base_param.variable_type.get_actual_type (object_type, method_type_args, this); if (!actual_base_type.equals (param.variable_type)) { invalid_match = "incompatible type of parameter %d".printf (param_index); return false; diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index 0229e40b7..23712a223 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -168,6 +168,8 @@ public class Vala.MethodCall : Expression { // type of target object DataType target_object_type = null; + List method_type_args = null; + if (call.value_type is DelegateType) { // delegate invocation, resolve generic types relative to delegate target_object_type = call.value_type; @@ -179,6 +181,8 @@ public class Vala.MethodCall : Expression { return false; } + method_type_args = ma.get_type_arguments (); + if (ma.inner != null) { target_object_type = ma.inner.value_type; @@ -396,7 +400,7 @@ public class Vala.MethodCall : Expression { /* store expected type for callback parameters */ arg.formal_target_type = param.variable_type; - arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this); + arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, method_type_args, this); last_arg = arg; } @@ -467,7 +471,7 @@ public class Vala.MethodCall : Expression { } formal_value_type = ret_type.copy (); - value_type = formal_value_type.get_actual_type (target_object_type, call as MemberAccess, this); + value_type = formal_value_type.get_actual_type (target_object_type, method_type_args, this); bool may_throw = false; @@ -541,7 +545,7 @@ public class Vala.MethodCall : Expression { break; } - arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this); + arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, method_type_args, this); } } @@ -569,12 +573,12 @@ public class Vala.MethodCall : Expression { if (arg_it.next ()) { Expression arg = arg_it.get (); - arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this); + arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, method_type_args, this); } } // recalculate return value type with new information - value_type = formal_value_type.get_actual_type (target_object_type, call as MemberAccess, this); + value_type = formal_value_type.get_actual_type (target_object_type, method_type_args, this); } } } else if (mtype is ObjectType) { diff --git a/vala/valapointertype.vala b/vala/valapointertype.vala index 461983c30..e3437f62e 100644 --- a/vala/valapointertype.vala +++ b/vala/valapointertype.vala @@ -123,15 +123,15 @@ public class Vala.PointerType : DataType { return false; } - public override DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) { + public override DataType get_actual_type (DataType? derived_instance_type, List? method_type_arguments, CodeNode node_reference) { PointerType result = (PointerType) this.copy (); - if (derived_instance_type == null && method_access == null) { + if (derived_instance_type == null && method_type_arguments == null) { return result; } if (base_type is GenericType || base_type.has_type_arguments ()) { - result.base_type = result.base_type.get_actual_type (derived_instance_type, method_access, node_reference); + result.base_type = result.base_type.get_actual_type (derived_instance_type, method_type_arguments, node_reference); } return result; diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index cb1a575f5..5a83c9b99 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -810,7 +810,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return null; } - public static DataType? get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, GenericType generic_type, CodeNode node_reference) { + public static DataType? get_actual_type (DataType? derived_instance_type, List? method_type_arguments, GenericType generic_type, CodeNode node_reference) { DataType actual_type = null; if (generic_type.type_parameter.parent_symbol is TypeSymbol) { if (derived_instance_type != null) { @@ -839,10 +839,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor { // generic method var m = (Method) generic_type.type_parameter.parent_symbol; - if (method_access == null) { - return generic_type; - } - int param_index = m.get_type_parameter_index (generic_type.type_parameter.name); if (param_index == -1) { Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name)); @@ -850,8 +846,10 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return null; } - if (param_index < method_access.get_type_arguments ().size) { - actual_type = (DataType) method_access.get_type_arguments ().get (param_index); + if (method_type_arguments != null) { + if (param_index < method_type_arguments.size) { + actual_type = (DataType) method_type_arguments.get (param_index); + } } } @@ -931,7 +929,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } init.initializer.formal_target_type = member_type; - init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init);; + init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init); init.check (context);