[vala] Support use of generics in closures



commit 837258146130818b9d02aba9ec63d586c611544d
Author: Jürg Billeter <j bitron ch>
Date:   Mon Oct 25 23:07:02 2010 +0200

    Support use of generics in closures

 codegen/valaccodebasemodule.vala   |   60 ++++++++++++++++++++++++++++-------
 codegen/valaccodemethodmodule.vala |   19 +++++++++++-
 vala/valalambdaexpression.vala     |   11 ++++++
 3 files changed, 77 insertions(+), 13 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 6fd4b7e..2045dff 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1727,13 +1727,31 @@ public class Vala.CCodeBaseModule : CodeGenerator {
 				var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
 				unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
 				free_block.add_statement (new CCodeExpressionStatement (unref_call));
-			} else if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE) ||
-			           (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
-				data.add_field ("%s *".printf (current_class.get_cname ()), "self");
+			} else {
+				if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE) ||
+				           (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
+					data.add_field ("%s *".printf (current_class.get_cname ()), "self");
+
+					var ma = new MemberAccess.simple ("this");
+					ma.symbol_reference = current_class;
+					free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self"), new ObjectType (current_class), ma)));
+				}
+
+				if (current_method != null) {
+					// allow capturing generic type parameters
+					foreach (var type_param in current_method.get_type_parameters ()) {
+						string func_name;
 
-				var ma = new MemberAccess.simple ("this");
-				ma.symbol_reference = current_class;
-				free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self"), new ObjectType (current_class), ma)));
+						func_name = "%s_type".printf (type_param.name.down ());
+						data.add_field ("GType", func_name);
+
+						func_name = "%s_dup_func".printf (type_param.name.down ());
+						data.add_field ("GBoxedCopyFunc", func_name);
+
+						func_name = "%s_destroy_func".printf (type_param.name.down ());
+						data.add_field ("GDestroyNotify", func_name);
+					}
+				}
 			}
 			foreach (var local in local_vars) {
 				if (local.captured) {
@@ -1799,13 +1817,31 @@ public class Vala.CCodeBaseModule : CodeGenerator {
 				ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
 
 				ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call));
-			} else if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE &&
-			                              (!(current_method is CreationMethod) || current_method.body != b)) ||
-			           (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
-				var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), b.source_reference));
-				ref_call.add_argument (get_result_cexpression ("self"));
+			} else {
+				if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE &&
+				                              (!(current_method is CreationMethod) || current_method.body != b)) ||
+				           (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
+					var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), b.source_reference));
+					ref_call.add_argument (get_result_cexpression ("self"));
+
+					ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), ref_call));
+				}
+
+				if (current_method != null) {
+					// allow capturing generic type parameters
+					foreach (var type_param in current_method.get_type_parameters ()) {
+						string func_name;
 
-				ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), ref_call));
+						func_name = "%s_type".printf (type_param.name.down ());
+						ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), new CCodeIdentifier (func_name)));
+
+						func_name = "%s_dup_func".printf (type_param.name.down ());
+						ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), new CCodeIdentifier (func_name)));
+
+						func_name = "%s_destroy_func".printf (type_param.name.down ());
+						ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), new CCodeIdentifier (func_name)));
+					}
+				}
 			}
 
 			if (b.parent_symbol is Method) {
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index a7022c2..a457f89 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -410,6 +410,23 @@ public class Vala.CCodeMethodModule : CCodeStructModule {
 						ccode.add_declaration ("%s *".printf (current_class.get_cname ()), new CCodeVariableDeclarator ("self"));
 						ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("self"), cself));
 					}
+
+					// allow capturing generic type parameters
+					foreach (var type_param in m.get_type_parameters ()) {
+						string func_name;
+
+						func_name = "%s_type".printf (type_param.name.down ());
+						ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
+						ccode.add_expression (new CCodeAssignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)));
+
+						func_name = "%s_dup_func".printf (type_param.name.down ());
+						ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
+						ccode.add_expression (new CCodeAssignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)));
+
+						func_name = "%s_destroy_func".printf (type_param.name.down ());
+						ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
+						ccode.add_expression (new CCodeAssignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)));
+					}
 				} else if (m.parent_symbol is Class && !m.coroutine) {
 					var cl = (Class) m.parent_symbol;
 					if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
@@ -828,7 +845,7 @@ public class Vala.CCodeMethodModule : CCodeStructModule {
 				}
 				type_param_index++;
 			}
-		} else {
+		} else if (!m.closure) {
 			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"));
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index d71c4b5..889905b 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -224,6 +224,17 @@ public class Vala.LambdaExpression : Expression {
 		}
 		method.body.owner = method.scope;
 
+		// support use of generics in closures
+		var m = analyzer.find_parent_method (analyzer.current_symbol);
+		if (m != null) {
+			foreach (var type_param in m.get_type_parameters ()) {
+				method.add_type_parameter (new TypeParameter (type_param.name, type_param.source_reference));
+
+				method.closure = true;
+				m.body.captured = true;
+			}
+		}
+
 		/* lambda expressions should be usable like MemberAccess of a method */
 		symbol_reference = method;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]