]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Add initial support for generic methods
authorJürg Billeter <j@bitron.ch>
Tue, 2 Jun 2009 15:26:29 +0000 (17:26 +0200)
committerJürg Billeter <j@bitron.ch>
Wed, 3 Jun 2009 07:24:59 +0000 (09:24 +0200)
Fixes bug 492483.

16 files changed:
codegen/valaccodebasemodule.vala
codegen/valaccodemethodcallmodule.vala
codegen/valaccodemethodmodule.vala
vala/valadatatype.vala
vala/valadelegate.vala
vala/valaforeachstatement.vala
vala/valamemberaccess.vala
vala/valamethod.vala
vala/valamethodcall.vala
vala/valaobjectcreationexpression.vala
vala/valaobjecttypesymbol.vala
vala/valaparser.vala
vala/valasemanticanalyzer.vala
vala/valasignal.vala
vala/valastruct.vala
vala/valatypeparameter.vala

index 79e37e27155e3317a175ceb9298487b0c296d2e5..bd639cb117e872a4a288690d70d0360984f68a40 100644 (file)
@@ -1719,7 +1719,11 @@ internal class Vala.CCodeBaseModule : CCodeModule {
        private CCodeExpression get_type_id_expression (DataType type) {
                if (type is GenericType) {
                        string var_name = "%s_type".printf (type.type_parameter.name.down ());
-                       return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), var_name);
+                       if (type.type_parameter.parent_symbol is TypeSymbol) {
+                               return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), var_name);
+                       } else {
+                               return new CCodeIdentifier (var_name);
+                       }
                } else {
                        string type_id = type.get_type_id ();
                        if (type_id == null) {
@@ -1765,7 +1769,11 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                        return new CCodeIdentifier (dup_function);
                } else if (type.type_parameter != null && current_type_symbol is Class) {
                        string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
-                       return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                       if (type.type_parameter.parent_symbol is TypeSymbol) {
+                               return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                       } else {
+                               return new CCodeIdentifier (func_name);
+                       }
                } else if (type is PointerType) {
                        var pointer_type = (PointerType) type;
                        return get_dup_func_expression (pointer_type.base_type, source_reference);
@@ -1891,7 +1899,11 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                        return new CCodeIdentifier (unref_function);
                } else if (type.type_parameter != null && current_type_symbol is Class) {
                        string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
-                       return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                       if (type.type_parameter.parent_symbol is TypeSymbol) {
+                               return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                       } else {
+                               return new CCodeIdentifier (func_name);
+                       }
                } else if (type is ArrayType) {
                        return new CCodeIdentifier ("g_free");
                } else if (type is PointerType) {
index 8e328ca516841ae6b55d432454c85b802f521399..adb4434541f66f53838451ccb51ba81f1bb68f8b 100644 (file)
@@ -98,34 +98,12 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 
                        foreach (DataType base_type in current_class.get_base_types ()) {
                                if (base_type.data_type is Class) {
-                                       foreach (DataType type_arg in base_type.get_type_arguments ()) {
-                                               if (type_arg is GenericType) {
-                                                       // map generic type parameter
-                                                       string type_param = type_arg.type_parameter.name.down ();
-                                                       ccall.add_argument (new CCodeIdentifier ("%s_type".printf (type_param)));
-                                                       ccall.add_argument (new CCodeIdentifier ("%s_dup_func".printf (type_param)));
-                                                       ccall.add_argument (new CCodeIdentifier ("%s_destroy_func".printf (type_param)));
-                                               } else {
-                                                       ccall.add_argument (new CCodeIdentifier (type_arg.get_type_id ()));
-                                                       if (requires_copy (type_arg)) {
-                                                               var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference);
-                                                               if (dup_func == null) {
-                                                                       // type doesn't contain a copy function
-                                                                       expr.error = true;
-                                                                       return;
-                                                               }
-                                                               ccall.add_argument (new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
-                                                               ccall.add_argument (get_destroy_func_expression (type_arg));
-                                                       } else {
-                                                               ccall.add_argument (new CCodeConstant ("NULL"));
-                                                               ccall.add_argument (new CCodeConstant ("NULL"));
-                                                       }
-                                               }
-                                       }
-
+                                       add_generic_type_arguments (ccall, base_type.get_type_arguments (), expr);
                                        break;
                                }
                        }
+               } else if (m != null && m.get_type_parameters ().size > 0) {
+                       add_generic_type_arguments (ccall, ma.get_type_arguments (), expr);
                }
 
                // the complete call expression, might include casts, comma expressions, and/or assignments
@@ -668,5 +646,32 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                        expr.ccodenode = ccomma;
                }
        }
+
+       void add_generic_type_arguments (CCodeFunctionCall ccall, Gee.List<DataType> type_args, CodeNode expr) {
+               foreach (var type_arg in type_args) {
+                       if (type_arg is GenericType) {
+                               // map generic type parameter
+                               string type_param = type_arg.type_parameter.name.down ();
+                               ccall.add_argument (new CCodeIdentifier ("%s_type".printf (type_param)));
+                               ccall.add_argument (new CCodeIdentifier ("%s_dup_func".printf (type_param)));
+                               ccall.add_argument (new CCodeIdentifier ("%s_destroy_func".printf (type_param)));
+                       } else {
+                               ccall.add_argument (new CCodeIdentifier (type_arg.get_type_id ()));
+                               if (requires_copy (type_arg)) {
+                                       var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference);
+                                       if (dup_func == null) {
+                                               // type doesn't contain a copy function
+                                               expr.error = true;
+                                               return;
+                                       }
+                                       ccall.add_argument (new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
+                                       ccall.add_argument (get_destroy_func_expression (type_arg));
+                               } else {
+                                       ccall.add_argument (new CCodeConstant ("NULL"));
+                                       ccall.add_argument (new CCodeConstant ("NULL"));
+                               }
+                       }
+               }
+       }
 }
 
index 26a51c34ac46dc1f1c895c6dd9be450763599a1c..0bd87c89c1a69fa00f9910eabb82d24a8ab2a03d 100644 (file)
@@ -740,6 +740,19 @@ internal class Vala.CCodeMethodModule : CCodeStructModule {
                                }
                                type_param_index++;
                        }
+               } else {
+                       int type_param_index = 0;
+                       foreach (var type_param in m.get_type_parameters ()) {
+                               cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "GType"));
+                               cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeFormalParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
+                               cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
+                               if (carg_map != null) {
+                                       carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+                                       carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
+                                       carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
+                               }
+                               type_param_index++;
+                       }
                }
 
                foreach (FormalParameter param in m.get_parameters ()) {
index 45af866065cdd47b1b70553f355f1b8646e03443..8150fb9c4bb46102adbf027c68149d32b721b985 100644 (file)
@@ -1,6 +1,7 @@
 /* valadatatype.vala
  *
- * Copyright (C) 2006-2008  Jürg Billeter, Raffaele Sandrini
+ * Copyright (C) 2006-2009  Jürg Billeter
+ * Copyright (C) 2006-2008  Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -477,22 +478,22 @@ public abstract class Vala.DataType : CodeNode {
                return false;
        }
 
-       public DataType get_actual_type (DataType? derived_instance_type, CodeNode node_reference) {
-               if (derived_instance_type == null) {
+       public DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) {
+               if (derived_instance_type == null && method_access == null) {
                        return this;
                }
 
                DataType result = this;
 
                if (result is GenericType) {
-                       result = SemanticAnalyzer.get_actual_type (derived_instance_type, (GenericType) result, node_reference);
+                       result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_access, (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
                        result = result.copy ();
                        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, node_reference);
+                               result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, method_access, node_reference);
                        }
                }
 
index d141ed0fcb55b91e67db524c30f72d61b07de9db..033058db72f1139681d70c860439167286810711 100644 (file)
@@ -107,7 +107,6 @@ public class Vala.Delegate : TypeSymbol {
         */
        public void add_type_parameter (TypeParameter p) {
                type_parameters.add (p);
-               p.type = this;
                scope.add (p.name, p);
        }
        
index 91bbd8580d9ca16b3f2de36a90212e6985d86727..78836c13680a1536cabf5d1037453775ebfc2528 100644 (file)
@@ -199,7 +199,7 @@ public class Vala.ForeachStatement : Block {
                        error = true;
                        return false;
                }
-               var iterator_type = iterator_method.return_type.get_actual_type (collection_type, this);
+               var iterator_type = iterator_method.return_type.get_actual_type (collection_type, null, this);
                if (iterator_type is VoidType) {
                        Report.error (collection.source_reference, "`%s' must return an iterator".printf (iterator_method.get_full_name ()));
                        error = true;
@@ -232,7 +232,7 @@ public class Vala.ForeachStatement : Block {
                        error = true;
                        return false;
                }
-               var element_type = get_method.return_type.get_actual_type (iterator_type, this);
+               var element_type = get_method.return_type.get_actual_type (iterator_type, null, this);
                if (element_type is VoidType) {
                        Report.error (collection.source_reference, "`%s' must return an element".printf (get_method.get_full_name ()));
                        error = true;
index 320ff50a16643810d8057723002be79fa63d4091..2ef15a4752f1e0f417f813b6b49414bc11b14e35 100644 (file)
@@ -547,7 +547,7 @@ public class Vala.MemberAccess : Expression {
 
                        formal_value_type = analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
                        if (inner != null && formal_value_type != null) {
-                               value_type = formal_value_type.get_actual_type (inner.value_type, this);
+                               value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
                        } else {
                                value_type = formal_value_type;
                        }
index 19e6c08b2afe522b1ce6edf1749fa6591ac42be9..5acfc655b72c29305f8f38f4297e35f00c52c60a 100644 (file)
@@ -29,6 +29,8 @@ using Gee;
  * Represents a type or namespace method.
  */
 public class Vala.Method : Member {
+       Gee.List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
+
        public const string DEFAULT_SENTINEL = "NULL";
 
        /**
@@ -422,7 +424,7 @@ public class Vala.Method : Member {
                        }
                }
 
-               var actual_base_type = base_method.return_type.get_actual_type (object_type, this);
+               var actual_base_type = base_method.return_type.get_actual_type (object_type, null, this);
                if (!return_type.equals (actual_base_type)) {
                        invalid_match = "incompatible return type";
                        return false;
@@ -437,7 +439,7 @@ public class Vala.Method : Member {
                                return false;
                        }
                        
-                       actual_base_type = base_param.parameter_type.get_actual_type (object_type, this);
+                       actual_base_type = base_param.parameter_type.get_actual_type (object_type, null, this);
                        if (!actual_base_type.equals (method_params_it.get ().parameter_type)) {
                                invalid_match = "incompatible type of parameter %d".printf (param_index);
                                return false;
@@ -470,6 +472,36 @@ public class Vala.Method : Member {
                return true;
        }
 
+       /**
+        * Appends the specified parameter to the list of type parameters.
+        *
+        * @param p a type parameter
+        */
+       public void add_type_parameter (TypeParameter p) {
+               type_parameters.add (p);
+               scope.add (p.name, p);
+       }
+
+       /**
+        * Returns a copy of the type parameter list.
+        *
+        * @return list of type parameters
+        */
+       public Gee.List<TypeParameter> get_type_parameters () {
+               return new ReadOnlyList<TypeParameter> (type_parameters);
+       }
+
+       public int get_type_parameter_index (string name) {
+               int i = 0;
+               foreach (TypeParameter parameter in type_parameters) {
+                       if (parameter.name == name) {
+                               return i;
+                       }
+                       i++;
+               }
+               return -1;
+       }
+
        /**
         * Adds a precondition to this method.
         *
index 670464d1db9ff4a0cceb437a7a7342390fb8e613..450f187fb57072c7e2fed0fc22528941b3cd3f9e 100644 (file)
@@ -238,7 +238,7 @@ public class Vala.MethodCall : Expression {
 
                                /* store expected type for callback parameters */
                                arg.formal_target_type = param.parameter_type;
-                               arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, this);
+                               arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this);
 
                                last_arg = arg;
                        }
@@ -399,7 +399,7 @@ public class Vala.MethodCall : Expression {
                }
 
                formal_value_type = ret_type;
-               value_type = formal_value_type.get_actual_type (target_object_type, this);
+               value_type = formal_value_type.get_actual_type (target_object_type, call as MemberAccess, this);
 
                bool may_throw = false;
 
index 20b829bdb6ce1bda534eece8c92612b47f1f1e6a..26d3bca3793804d5957dfeaf4ea7ab5444147092 100644 (file)
@@ -308,7 +308,7 @@ public class Vala.ObjectCreationExpression : Expression {
 
                                        /* store expected type for callback parameters */
                                        arg.formal_target_type = param.parameter_type;
-                                       arg.target_type = arg.formal_target_type.get_actual_type (value_type, this);
+                                       arg.target_type = arg.formal_target_type.get_actual_type (value_type, null, this);
                                }
                        }
 
index 6f51e9751a72689a19f59a0e9768e4f37256d7fd..752290c9f64184221e012662c45f70d2b856055a 100644 (file)
@@ -1,6 +1,6 @@
 /* valaobjecttypesymbol.vala
  *
- * Copyright (C) 2008  Jürg Billeter
+ * Copyright (C) 2008-2009  Jürg Billeter
  * Copyright (C) 2008  Philip Van Hoof
  *
  * This library is free software; you can redistribute it and/or
@@ -47,7 +47,6 @@ public abstract class Vala.ObjectTypeSymbol : TypeSymbol {
         */
        public void add_type_parameter (TypeParameter p) {
                type_parameters.add (p);
-               p.type = this;
                scope.add (p.name, p);
        }
 
index 5e7d92c1c0dd4c21458decead643e2e984946975..085e9271e158975f1fa24152154c13c845bfc181 100644 (file)
@@ -2160,10 +2160,13 @@ public class Vala.Parser : CodeVisitor {
                var flags = parse_member_declaration_modifiers ();
                var type = parse_type ();
                string id = parse_identifier ();
-               parse_type_parameter_list ();
+               var type_param_list = parse_type_parameter_list ();
                var method = new Method (id, type, get_src_com (begin));
                method.access = access;
                set_attributes (method, attrs);
+               foreach (TypeParameter type_param in type_param_list) {
+                       method.add_type_parameter (type_param);
+               }
                if (ModifierFlags.STATIC in flags) {
                        method.binding = MemberBinding.STATIC;
                } else if (ModifierFlags.CLASS in flags) {
index 47f806a96212fd3670f423e027b6aa16355cce27..1bef37711d8f21ee691356bfe904965bb5e9036d 100644 (file)
@@ -551,30 +551,62 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return null;
        }
 
-       public static DataType? get_actual_type (DataType derived_instance_type, GenericType generic_type, CodeNode node_reference) {
-               // trace type arguments back to the datatype where the method has been declared
-               var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
+       public static DataType? get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, GenericType generic_type, CodeNode node_reference) {
+               if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
+                       if (derived_instance_type == null) {
+                               return generic_type;
+                       }
 
-               assert (instance_type != null);
+                       // trace type arguments back to the datatype where the method has been declared
+                       var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
 
-               int param_index = instance_type.data_type.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));
-                       node_reference.error = true;
-                       return null;
-               }
+                       assert (instance_type != null);
 
-               DataType actual_type = null;
-               if (param_index < instance_type.get_type_arguments ().size) {
-                       actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
-               }
-               if (actual_type == null) {
-                       // no actual type available
-                       return generic_type;
+                       int param_index = instance_type.data_type.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));
+                               node_reference.error = true;
+                               return null;
+                       }
+
+                       DataType actual_type = null;
+                       if (param_index < instance_type.get_type_arguments ().size) {
+                               actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
+                       }
+                       if (actual_type == null) {
+                               // no actual type available
+                               return generic_type;
+                       }
+                       actual_type = actual_type.copy ();
+                       actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
+                       return actual_type;
+               } else {
+                       // 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));
+                               node_reference.error = true;
+                               return null;
+                       }
+
+                       DataType actual_type = null;
+                       if (param_index < method_access.get_type_arguments ().size) {
+                               actual_type = (DataType) method_access.get_type_arguments ().get (param_index);
+                       }
+                       if (actual_type == null) {
+                               // no actual type available
+                               return generic_type;
+                       }
+                       actual_type = actual_type.copy ();
+                       actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
+                       return actual_type;
                }
-               actual_type = actual_type.copy ();
-               actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
-               return actual_type;
        }
 
        public bool is_in_instance_method () {
index 58f54ef2a7f43bbcbd79ca72cf7f85b4b6400407..9b85e89b901f736d2af6ccb8e330cc2cc9d2672f 100644 (file)
@@ -95,7 +95,7 @@ public class Vala.Signal : Member, Lockable {
         * @return delegate
         */
        public Delegate get_delegate (DataType sender_type, CodeNode node_reference) {
-               var actual_return_type = return_type.get_actual_type (sender_type, node_reference);
+               var actual_return_type = return_type.get_actual_type (sender_type, null, node_reference);
 
                var generated_delegate = new Delegate (null, actual_return_type);
                generated_delegate.has_target = true;
@@ -111,7 +111,7 @@ public class Vala.Signal : Member, Lockable {
 
                foreach (FormalParameter param in parameters) {
                        var actual_param = param.copy ();
-                       actual_param.parameter_type = actual_param.parameter_type.get_actual_type (sender_type, node_reference);
+                       actual_param.parameter_type = actual_param.parameter_type.get_actual_type (sender_type, null, node_reference);
                        generated_delegate.add_parameter (actual_param);
                }
 
index 684425a4cd9f077943eaa8f1349c47a6405196ae..f715b3b03fbaef1b4c6cfeada97f818944625db5 100644 (file)
@@ -113,7 +113,6 @@ public class Vala.Struct : TypeSymbol {
         */
        public void add_type_parameter (TypeParameter p) {
                type_parameters.add (p);
-               p.type = this;
                scope.add (p.name, p);
        }
        
index 8985ea8a26e6490a845e7301ad66310f0dea0d85..623044a75c5ff17762158004c7264e05c443e506 100644 (file)
@@ -1,6 +1,6 @@
 /* valatypeparameter.vala
  *
- * Copyright (C) 2006-2008  Jürg Billeter
+ * Copyright (C) 2006-2009  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,11 +27,6 @@ using Gee;
  * Represents a generic type parameter in the source code.
  */
 public class Vala.TypeParameter : Symbol {
-       /**
-        * The generic type declaring this parameter.
-        */
-       public weak TypeSymbol type;
-
        /**
         * Creates a new generic type parameter.
         *