]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Fix type parameter check for overriding generic methods
authorJürg Billeter <j@bitron.ch>
Mon, 26 Sep 2016 17:07:17 +0000 (19:07 +0200)
committerJürg Billeter <j@bitron.ch>
Mon, 26 Sep 2016 18:09:00 +0000 (20:09 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=771964

Reported-by: Sebastian Reichel <sre@ring0.de>
tests/Makefile.am
tests/methods/bug771964.vala [new file with mode: 0644]
vala/valaarraytype.vala
vala/valadatatype.vala
vala/valamethod.vala
vala/valamethodcall.vala
vala/valapointertype.vala
vala/valasemanticanalyzer.vala

index d4f0fc3c72d6acc5024b93116b5cfa4611979749..4e684a75d265154590ba1bf73be8778c304cc0d9 100644 (file)
@@ -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 (file)
index 0000000..f760e12
--- /dev/null
@@ -0,0 +1,15 @@
+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;
+}
index d993e3c9372869a37b86315e6092d953da2e0b51..f6d01329241ec2d83e6feffaea81b1ee6d207f74 100644 (file)
@@ -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;
index 02b4cf13f79587ef5a415efc965dc01fca65aedd..2277224facab577892bf57b7b326f9d289be44d3 100644 (file)
@@ -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);
                        }
                }
 
index d9aba3e6ce647e1268116cd9375f6c25f622a811..7c883b5cdadf35050bf0764877f471edfa960da4 100644 (file)
@@ -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;
index 0229e40b72c87b7b6e83fa2a4e08c7cd9811e176..23712a2230ce12f3846a2798aebb816837976096 100644 (file)
@@ -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) {
index 461983c302daf28321b9944ddb48cfaeb1439921..e3437f62e8ddd53215bf645210660b73ee5c537a 100644 (file)
@@ -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;
index cb1a575f59674f0af8e70021070f8d10d070bb2a..5a83c9b993ec3dc07b04e8b256f623e6f867fbd8 100644 (file)
@@ -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);