Getting colder with our second freeze... it's 3.31.91 release day and string freeze, upload a tarball and lock those strings 🏂

Commit dadf2b48 authored by Jürg Billeter's avatar Jürg Billeter

Fix type parameter check for overriding generic methods

https://bugzilla.gnome.org/show_bug.cgi?id=771964Reported-by: 's avatarSebastian Reichel <sre@ring0.de>
parent ad9fa2ab
......@@ -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 \
......
public abstract class Foo : Object {
public abstract void test<T> (T parameter);
}
public class Bar : Foo {
public override void test<T> (T parameter) {
stdout.printf ("Just a test!\n");
}
}
int main () {
var obj = new Bar();
obj.test<string> ("test");
return 0;
}
......@@ -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<DataType>? 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;
......
......@@ -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<DataType>? 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);
}
}
......
......@@ -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<DataType> method_type_args = null;
if (this.get_type_parameters ().size > 0) {
method_type_args = new ArrayList<DataType> ();
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;
......
......@@ -168,6 +168,8 @@ public class Vala.MethodCall : Expression {
// type of target object
DataType target_object_type = null;
List<DataType> 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) {
......
......@@ -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<DataType>? 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;
......
......@@ -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<DataType>? 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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment