[vala] Add initial support for generic methods
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Subject: [vala] Add initial support for generic methods
- Date: Wed, 3 Jun 2009 03:26:51 -0400 (EDT)
commit 37c82ec971b2b200f3d7ca188d1c91d0f34a3f9f
Author: Jürg Billeter <j bitron ch>
Date: Tue Jun 2 17:26:29 2009 +0200
Add initial support for generic methods
Fixes bug 492483.
---
codegen/valaccodebasemodule.vala | 18 +++++++-
codegen/valaccodemethodcallmodule.vala | 55 +++++++++++++-----------
codegen/valaccodemethodmodule.vala | 13 ++++++
vala/valadatatype.vala | 11 +++--
vala/valadelegate.vala | 1 -
vala/valaforeachstatement.vala | 4 +-
vala/valamemberaccess.vala | 2 +-
vala/valamethod.vala | 36 +++++++++++++++-
vala/valamethodcall.vala | 4 +-
vala/valaobjectcreationexpression.vala | 2 +-
vala/valaobjecttypesymbol.vala | 3 +-
vala/valaparser.vala | 5 ++-
vala/valasemanticanalyzer.vala | 72 +++++++++++++++++++++++---------
vala/valasignal.vala | 4 +-
vala/valastruct.vala | 1 -
vala/valatypeparameter.vala | 7 +---
16 files changed, 164 insertions(+), 74 deletions(-)
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 79e37e2..bd639cb 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -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) {
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 8e328ca..adb4434 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -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"));
+ }
+ }
+ }
+ }
}
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 26a51c3..0bd87c8 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -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 ()) {
diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala
index 45af866..8150fb9 100644
--- a/vala/valadatatype.vala
+++ b/vala/valadatatype.vala
@@ -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);
}
}
diff --git a/vala/valadelegate.vala b/vala/valadelegate.vala
index d141ed0..033058d 100644
--- a/vala/valadelegate.vala
+++ b/vala/valadelegate.vala
@@ -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);
}
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
index 91bbd85..78836c1 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -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;
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 320ff50..2ef15a4 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -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;
}
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 19e6c08..5acfc65 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -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;
@@ -471,6 +473,36 @@ public class Vala.Method : Member {
}
/**
+ * 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.
*
* @param precondition a boolean precondition expression
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index 670464d..450f187 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -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;
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index 20b829b..26d3bca 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -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);
}
}
diff --git a/vala/valaobjecttypesymbol.vala b/vala/valaobjecttypesymbol.vala
index 6f51e97..752290c 100644
--- a/vala/valaobjecttypesymbol.vala
+++ b/vala/valaobjecttypesymbol.vala
@@ -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);
}
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 5e7d92c..085e927 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -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) {
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 47f806a..1bef377 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -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 () {
diff --git a/vala/valasignal.vala b/vala/valasignal.vala
index 58f54ef..9b85e89 100644
--- a/vala/valasignal.vala
+++ b/vala/valasignal.vala
@@ -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);
}
diff --git a/vala/valastruct.vala b/vala/valastruct.vala
index 684425a..f715b3b 100644
--- a/vala/valastruct.vala
+++ b/vala/valastruct.vala
@@ -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);
}
diff --git a/vala/valatypeparameter.vala b/vala/valatypeparameter.vala
index 8985ea8..623044a 100644
--- a/vala/valatypeparameter.vala
+++ b/vala/valatypeparameter.vala
@@ -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
@@ -28,11 +28,6 @@ using Gee;
*/
public class Vala.TypeParameter : Symbol {
/**
- * The generic type declaring this parameter.
- */
- public weak TypeSymbol type;
-
- /**
* Creates a new generic type parameter.
*
* @param name parameter name
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]