[vala] Fix methods returning owned delegates



commit f3f62d0591f6b77851b3a243e867f1df91cb899b
Author: Jürg Billeter <j bitron ch>
Date:   Fri Sep 18 12:49:34 2009 +0200

    Fix methods returning owned delegates

 codegen/valaccodeassignmentmodule.vala |    8 +++-
 codegen/valaccodebasemodule.vala       |   51 ++++++++++++++++++++++----
 codegen/valaccodedelegatemodule.vala   |   58 ++++++++++++++++++++++++++---
 codegen/valaccodemethodcallmodule.vala |   62 +++++++++++---------------------
 codegen/valaccodemethodmodule.vala     |    7 ++++
 codegen/valagsignalmodule.vala         |   13 ++-----
 vala/valadelegatetype.vala             |   13 ++++++-
 vala/valaexpression.vala               |    3 +-
 vala/valalambdaexpression.vala         |    1 +
 9 files changed, 146 insertions(+), 70 deletions(-)
---
diff --git a/codegen/valaccodeassignmentmodule.vala b/codegen/valaccodeassignmentmodule.vala
index 371e8c1..9ae2690 100644
--- a/codegen/valaccodeassignmentmodule.vala
+++ b/codegen/valaccodeassignmentmodule.vala
@@ -165,9 +165,13 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
 					}
 				}
 			} else if (instance_delegate) {
-				var lhs_delegate_target = get_delegate_target_cexpression (assignment.left);
-				var rhs_delegate_target = get_delegate_target_cexpression (assignment.right);
+				CCodeExpression lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify;
+				var lhs_delegate_target = get_delegate_target_cexpression (assignment.left, out lhs_delegate_target_destroy_notify);
+				var rhs_delegate_target = get_delegate_target_cexpression (assignment.right, out rhs_delegate_target_destroy_notify);
 				ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
+				if (assignment.right.target_type.value_owned) {
+					ccomma.append_expression (new CCodeAssignment (lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify));
+				}
 			}
 			
 			ccomma.append_expression (get_variable_cexpression (temp_decl.name));
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 051651a..1b686c4 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1648,6 +1648,9 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 						}
 					} else if (local.variable_type is DelegateType) {
 						data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local.name)));
+						if (local.variable_type.value_owned) {
+							data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
+						}
 					}
 
 					if (requires_destroy (local.variable_type)) {
@@ -1721,6 +1724,10 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 						} else if (param.parameter_type is DelegateType) {
 							data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param.name)));
 							cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_delegate_target_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name))))));
+							if (param.parameter_type.value_owned) {
+								data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
+								cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))))));
+							}
 						}
 
 						if (requires_destroy (param_type)) {
@@ -1889,6 +1896,10 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 				// create variable to store delegate target
 				var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_variable_cname (local.name)));
 				temp_vars.insert (0, target_var);
+				if (deleg_type.value_owned) {
+					var target_destroy_notify_var = new LocalVariable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")), get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
+					temp_vars.insert (0, target_destroy_notify_var);
+				}
 			}
 		}
 	
@@ -1938,11 +1949,21 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 						var block = (Block) local.parent_symbol;
 						lhs_delegate_target = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (local.name));
 					}
-					var rhs_delegate_target = get_delegate_target_cexpression (local.initializer);
+					CCodeExpression rhs_delegate_target_destroy_notify;
+					var rhs_delegate_target = get_delegate_target_cexpression (local.initializer, out rhs_delegate_target_destroy_notify);
 					ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
-				
+
+					if (deleg_type.value_owned) {
+						var lhs_delegate_target_destroy_notify = get_variable_cexpression (get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
+						if (local.captured) {
+							var block = (Block) local.parent_symbol;
+							lhs_delegate_target = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (local.name));
+						}
+						ccomma.append_expression (new CCodeAssignment (lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify));
+					}
+
 					ccomma.append_expression (get_variable_cexpression (temp_var.name));
-				
+
 					rhs = ccomma;
 				}
 			}
@@ -2831,8 +2852,16 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 					if (current_method == null || !current_method.coroutine) {
 						target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
 					}
-					var target_r = get_delegate_target_cexpression (stmt.return_expression);
+					CCodeExpression target_r_destroy_notify;
+					var target_r = get_delegate_target_cexpression (stmt.return_expression, out target_r_destroy_notify);
 					ccomma.append_expression (new CCodeAssignment (target_l, target_r));
+					if (delegate_type.value_owned) {
+						var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
+						if (current_method == null || !current_method.coroutine) {
+							target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
+						}
+						ccomma.append_expression (new CCodeAssignment (target_l_destroy_notify, target_r_destroy_notify));
+					}
 
 					ccomma.append_expression (get_variable_cexpression (return_expr_decl.name));
 
@@ -3011,7 +3040,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		assert_not_reached ();
 	}
 
-	public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr) {
+	public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
 		assert_not_reached ();
 	}
 
@@ -3511,8 +3540,12 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 							var deleg_type = (DelegateType) param.parameter_type;
 							var d = deleg_type.delegate_symbol;
 							if (d.has_target) {
-								var delegate_target = get_delegate_target_cexpression (arg);
+								CCodeExpression delegate_target_destroy_notify;
+								var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
 								carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
+								if (deleg_type.value_owned) {
+									carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
+								}
 							}
 						}
 
@@ -3658,7 +3691,8 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 						} else {
 							lhs = new CCodeMemberAccess.pointer (typed_inst, get_delegate_target_cname (f.get_cname ()));
 						}
-						var rhs_delegate_target = get_delegate_target_cexpression (init.initializer);
+						CCodeExpression rhs_delegate_target_destroy_notify;
+						var rhs_delegate_target = get_delegate_target_cexpression (init.initializer, out rhs_delegate_target_destroy_notify);
 						ccomma.append_expression (new CCodeAssignment (lhs, rhs_delegate_target));
 					}
 				} else if (init.symbol_reference is Property) {
@@ -4316,7 +4350,8 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		} else if (prop.property_type is DelegateType && rhs != null) {
 			var delegate_type = (DelegateType) prop.property_type;
 			if (delegate_type.delegate_symbol.has_target) {
-				ccall.add_argument (get_delegate_target_cexpression (rhs));
+				CCodeExpression delegate_target_destroy_notify;
+				ccall.add_argument (get_delegate_target_cexpression (rhs, out delegate_target_destroy_notify));
 			}
 		}
 
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index 182cf5a..85d9ea9 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -123,9 +123,11 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 		return "%s_target".printf (delegate_cname);
 	}
 
-	public override CCodeExpression get_delegate_target_cexpression (Expression delegate_expr) {
+	public override CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
 		bool is_out = false;
 	
+		delegate_target_destroy_notify = new CCodeConstant ("NULL");
+
 		if (delegate_expr is UnaryExpression) {
 			var unary_expr = (UnaryExpression) delegate_expr;
 			if (unary_expr.operator == UnaryOperator.OUT || unary_expr.operator == UnaryOperator.REF) {
@@ -136,6 +138,9 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 		
 		if (delegate_expr is MethodCall) {
 			var invocation_expr = (MethodCall) delegate_expr;
+			if (invocation_expr.delegate_target_destroy_notify != null) {
+				delegate_target_destroy_notify = invocation_expr.delegate_target_destroy_notify;
+			}
 			return invocation_expr.delegate_target;
 		} else if (delegate_expr is LambdaExpression) {
 			var closure_block = current_symbol as Block;
@@ -143,9 +148,32 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				closure_block = closure_block.parent_symbol as Block;
 			}
 			if (closure_block != null) {
-				return get_variable_cexpression ("_data%d_".printf (get_block_id (closure_block)));
+				int block_id = get_block_id (closure_block);
+				var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
+				if (delegate_expr.value_type.value_owned) {
+					var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
+					ref_call.add_argument (delegate_target);
+					delegate_target = ref_call;
+					delegate_target_destroy_notify = new CCodeIdentifier ("block%d_data_unref".printf (block_id));
+				}
+				return delegate_target;
 			} else if (get_this_type () != null || in_constructor) {
-				return new CCodeIdentifier ("self");
+				CCodeExpression delegate_target = new CCodeIdentifier ("self");
+				if (delegate_expr.value_type.value_owned) {
+					if (get_this_type () != null) {
+						var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), delegate_expr.source_reference));
+						ref_call.add_argument (delegate_target);
+						delegate_target = ref_call;
+						delegate_target_destroy_notify = get_destroy_func_expression (get_this_type ());
+					} else {
+						// in constructor
+						var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
+						ref_call.add_argument (delegate_target);
+						delegate_target = ref_call;
+						delegate_target_destroy_notify = new CCodeIdentifier ("g_object_unref");
+					}
+				}
+				return delegate_target;
 			} else {
 				return new CCodeConstant ("NULL");
 			}
@@ -155,17 +183,22 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				if (param.captured) {
 					// captured variables are stored on the heap
 					var block = ((Method) param.parent_symbol).body;
+					delegate_target_destroy_notify = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
 					return new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (get_variable_cname (param.name)));
 				} else if (current_method != null && current_method.coroutine) {
+					delegate_target_destroy_notify = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
 					return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param.name)));
 				} else {
 					CCodeExpression target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name)));
+					delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
 					if (param.direction != ParameterDirection.IN) {
 						// accessing argument of out/ref param
 						target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
+						delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
 					}
 					if (is_out) {
-						// passing array as out/ref
+						// passing delegate as out/ref
+						delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, delegate_target_destroy_notify);
 						return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
 					} else {
 						return target_expr;
@@ -176,12 +209,16 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				if (local.captured) {
 					// captured variables are stored on the heap
 					var block = (Block) local.parent_symbol;
+					delegate_target_destroy_notify = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
 					return new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (get_variable_cname (local.name)));
 				} else if (current_method != null && current_method.coroutine) {
+					delegate_target_destroy_notify = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
 					return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (local.name)));
 				} else {
 					var target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (local.name)));
+					delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
 					if (is_out) {
+						delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, delegate_target_destroy_notify);
 						return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
 					} else {
 						return target_expr;
@@ -230,7 +267,14 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				} else if (m.is_async_callback) {
 					return new CCodeIdentifier ("data");
 				} else {
-					return (CCodeExpression) get_ccodenode (ma.inner);
+					var delegate_target = (CCodeExpression) get_ccodenode (ma.inner);
+					if (ma.inner.value_type.data_type != null && ma.inner.value_type.data_type.is_reference_counting ()) {
+						var ref_call = new CCodeFunctionCall (get_dup_func_expression (ma.inner.value_type, delegate_expr.source_reference));
+						ref_call.add_argument (delegate_target);
+						delegate_target = ref_call;
+						delegate_target_destroy_notify = get_destroy_func_expression (ma.inner.value_type);
+					}
+					return delegate_target;
 				}
 			} else if (delegate_expr.symbol_reference is Property) {
 				return delegate_expr.delegate_target;
@@ -471,6 +515,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 
 		string ctypename = param.parameter_type.get_cname ();
 		string target_ctypename = "void*";
+		string target_destroy_notify_ctypename = "GDestroyNotify";
 
 		if (param.parent_symbol is Delegate
 		    && param.parameter_type.get_cname () == ((Delegate) param.parent_symbol).get_cname ()) {
@@ -481,6 +526,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 		if (param.direction != ParameterDirection.IN) {
 			ctypename += "*";
 			target_ctypename += "*";
+			target_destroy_notify_ctypename += "*";
 		}
 
 		param.ccodenode = new CCodeFormalParameter (get_variable_cname (param.name), ctypename);
@@ -503,7 +549,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 					carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_variable_cexpression (cparam.name));
 				}
 				if (deleg_type.value_owned) {
-					cparam = new CCodeFormalParameter (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)), "GDestroyNotify");
+					cparam = new CCodeFormalParameter (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)), target_destroy_notify_ctypename);
 					cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), cparam);
 					if (carg_map != null) {
 						carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), get_variable_cexpression (cparam.name));
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index c47c4bc..31d145e 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -289,50 +289,18 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 						var deleg_type = (DelegateType) param.parameter_type;
 						var d = deleg_type.delegate_symbol;
 						if (d.has_target) {
-							var delegate_target = get_delegate_target_cexpression (arg);
+							CCodeExpression delegate_target_destroy_notify;
+							var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
+							carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
 							if (deleg_type.value_owned) {
-								CCodeExpression delegate_target_destroy_notify;
-								var delegate_method = arg.symbol_reference as Method;
-								var lambda = arg as LambdaExpression;
-								var arg_ma = arg as MemberAccess;
-								if (lambda != null) {
-									if (delegate_method.closure) {
-										var closure_block = current_symbol as Block;
-										while (closure_block != null && !closure_block.captured) {
-											closure_block = closure_block.parent_symbol as Block;
-										}
-										int block_id = get_block_id (closure_block);
-										var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
-										ref_call.add_argument (delegate_target);
-										delegate_target = ref_call;
-										delegate_target_destroy_notify = new CCodeIdentifier ("block%d_data_unref".printf (block_id));
-									} else if (get_this_type () != null) {
-										// type of delegate target is same as `this'
-										// for lambda expressions in instance methods
-										var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), arg.source_reference));
-										ref_call.add_argument (delegate_target);
-										delegate_target = ref_call;
-										delegate_target_destroy_notify = get_destroy_func_expression (get_this_type ());
-									} else {
-										delegate_target_destroy_notify = new CCodeConstant ("NULL");
-									}
-								} else if (delegate_method != null && delegate_method.binding == MemberBinding.INSTANCE
-								           && arg_ma != null && arg_ma.inner != null && arg_ma.inner.value_type.data_type != null
-								           && arg_ma.inner.value_type.data_type.is_reference_counting ()) {
-									var ref_call = new CCodeFunctionCall (get_dup_func_expression (arg_ma.inner.value_type, arg.source_reference));
-									ref_call.add_argument (delegate_target);
-									delegate_target = ref_call;
-									delegate_target_destroy_notify = get_destroy_func_expression (arg_ma.inner.value_type);
-								} else {
-									delegate_target_destroy_notify = new CCodeConstant ("NULL");
-								}
 								carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
- 							}
-							carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
+							}
 							multiple_cargs = true;
 						}
 					} else if (param.parameter_type is MethodType) {
-						carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_delegate_target_cexpression (arg));
+						// callbacks in dynamic method calls
+						CCodeExpression delegate_target_destroy_notify;
+						carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
 						multiple_cargs = true;
 					}
 
@@ -485,6 +453,17 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 				out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
 
 				expr.delegate_target = temp_ref;
+
+				if (deleg_type.value_owned) {
+					temp_var = get_temp_variable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")));
+					temp_ref = get_variable_cexpression (temp_var.name);
+
+					temp_vars.insert (0, temp_var);
+
+					out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
+
+					expr.delegate_target_destroy_notify = temp_ref;
+				}
 			}
 		}
 
@@ -562,8 +541,9 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 			var deleg_type = (DelegateType) itype;
 			var d = deleg_type.delegate_symbol;
 			if (d.has_target) {
-				in_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call));
-				out_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call));
+				CCodeExpression delegate_target_destroy_notify;
+				in_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
+				out_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
 			}
 		}
 
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 0a846b6..363c6c4 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -111,6 +111,13 @@ internal class Vala.CCodeMethodModule : CCodeStructModule {
 				if (carg_map != null) {
 					carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), get_variable_cexpression (cparam.name));
 				}
+				if (deleg_type.value_owned) {
+					cparam = new CCodeFormalParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
+					cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), cparam);
+					if (carg_map != null) {
+						carg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), get_variable_cexpression (cparam.name));
+					}
+				}
 			}
 		}
 
diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala
index 64b447f..2387b12 100644
--- a/codegen/valagsignalmodule.vala
+++ b/codegen/valagsignalmodule.vala
@@ -652,19 +652,12 @@ internal class Vala.GSignalModule : GObjectModule {
 		if (m.closure) {
 			// g_signal_connect_data
 
-			var closure_block = current_symbol as Block;
-			while (closure_block != null && !closure_block.captured) {
-				closure_block = closure_block.parent_symbol as Block;
-			}
-			int block_id = get_block_id (closure_block);
-
 			// fourth argument: user_data
-			var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
-			ref_call.add_argument (get_delegate_target_cexpression (handler));
-			ccall.add_argument (new CCodeCastExpression (ref_call, "GCallback"));
+			CCodeExpression handler_destroy_notify;
+			ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify));
 
 			// fifth argument: destroy_notify
-			ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("block%d_data_unref".printf (block_id)), "GClosureNotify"));
+			ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify"));
 
 			// sixth argument: connect_flags
 			ccall.add_argument (new CCodeConstant ("0"));
diff --git a/vala/valadelegatetype.vala b/vala/valadelegatetype.vala
index 40035d9..1f32a7e 100644
--- a/vala/valadelegatetype.vala
+++ b/vala/valadelegatetype.vala
@@ -1,6 +1,6 @@
 /* valadelegatetype.vala
  *
- * Copyright (C) 2007-2008  Jürg Billeter
+ * Copyright (C) 2007-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
@@ -54,7 +54,16 @@ public class Vala.DelegateType : DataType {
 	}
 
 	public override DataType copy () {
-		return new DelegateType (delegate_symbol);
+		var result = new DelegateType (delegate_symbol);
+		result.source_reference = source_reference;
+		result.value_owned = value_owned;
+		result.nullable = nullable;
+
+		foreach (DataType arg in get_type_arguments ()) {
+			result.add_type_argument (arg.copy ());
+		}
+
+		return result;
 	}
 
 	public override string? get_cname () {
diff --git a/vala/valaexpression.vala b/vala/valaexpression.vala
index 4313499..a97ed10 100644
--- a/vala/valaexpression.vala
+++ b/vala/valaexpression.vala
@@ -66,7 +66,8 @@ public abstract class Vala.Expression : CodeNode {
 
 	private Gee.List<CCodeExpression> array_sizes = new ArrayList<CCodeExpression> ();
 
-	public CCodeExpression delegate_target { get; set; }
+	public CCodeExpression? delegate_target { get; set; }
+	public CCodeExpression? delegate_target_destroy_notify { get; set; }
 
 	/**
 	 * Returns whether this expression is constant, i.e. whether this
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index 16a51c1..c9794c2 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -223,6 +223,7 @@ public class Vala.LambdaExpression : Expression {
 		}
 
 		value_type = new MethodType (method);
+		value_type.value_owned = target_type.value_owned;
 
 		return !error;
 	}



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