[vala] GAsync: Support async creation methods



commit 6be0b6a71b3fa53a38eb0fc055d1ea952ec973f7
Author: JÃrg Billeter <j bitron ch>
Date:   Sun Jun 24 20:50:44 2012 +0200

    GAsync: Support async creation methods
    
    Fixes bug 659886.

 codegen/valaccodebasemodule.vala       |  112 ++++++++++++++++++++++-----
 codegen/valaccodemethodcallmodule.vala |   12 ++--
 codegen/valaccodemethodmodule.vala     |   20 +++--
 codegen/valagasyncmodule.vala          |  136 +++++++++++++++++++++++++++++---
 vala/valaobjectcreationexpression.vala |    2 +
 vala/valaparser.vala                   |   13 +++-
 6 files changed, 246 insertions(+), 49 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index ccaca21..7c4d28b 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -2129,6 +2129,14 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 		}
 	}
 
+	public CCodeExpression get_this_cexpression () {
+		if (is_in_coroutine ()) {
+			return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
+		} else {
+			return new CCodeIdentifier ("self");
+		}
+	}
+
 	public string get_local_cname (LocalVariable local) {
 		var cname = get_variable_cname (local.name);
 		if (is_in_coroutine ()) {
@@ -3532,9 +3540,9 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 			// do not call return as member cleanup and chain up to base finalizer
 			// stil need to be executed
 			ccode.add_goto ("_return");
+		} else if (is_in_coroutine ()) {
 		} else if (current_method is CreationMethod) {
 			ccode.add_return (new CCodeIdentifier ("self"));
-		} else if (is_in_coroutine ()) {
 		} else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
 			// structs are returned via out parameter
 			ccode.add_return ();
@@ -4332,6 +4340,9 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 			var params = m.get_parameters ();
 			CCodeFunctionCall creation_call;
 
+			CCodeFunctionCall async_call = null;
+			CCodeFunctionCall finish_call = null;
+
 			generate_method_declaration (m, cfile);
 
 			var cl = expr.type_reference.data_type as Class;
@@ -4362,17 +4373,32 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
 			generate_type_declaration (expr.type_reference, cfile);
 
-			var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+			var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+			var out_arg_map = in_arg_map;
+
+			if (m != null && m.coroutine) {
+				// async call
+
+				async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
+				finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
+
+				creation_call = finish_call;
+
+				// output arguments used separately
+				out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+				// pass GAsyncResult stored in closure to finish function
+				out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
+			}
 
 			if (cl != null && !cl.is_compact) {
-				add_generic_type_arguments (carg_map, expr.type_reference.get_type_arguments (), expr);
+				add_generic_type_arguments (in_arg_map, expr.type_reference.get_type_arguments (), expr);
 			} else if (cl != null && get_ccode_simple_generics (m)) {
 				int type_param_index = 0;
 				foreach (var type_arg in expr.type_reference.get_type_arguments ()) {
 					if (requires_copy (type_arg)) {
-						carg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
+						in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
 					} else {
-						carg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
+						in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
 					}
 					type_param_index++;
 				}
@@ -4385,11 +4411,18 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 			Iterator<Parameter> params_it = params.iterator ();
 			foreach (Expression arg in expr.get_argument_list ()) {
 				CCodeExpression cexpr = get_cvalue (arg);
+
+				var carg_map = in_arg_map;
+
 				Parameter param = null;
 				if (params_it.next ()) {
 					param = params_it.get ();
 					ellipsis = param.ellipsis;
 					if (!ellipsis) {
+						if (param.direction == ParameterDirection.OUT) {
+							carg_map = out_arg_map;
+						}
+
 						// g_array_new: element size
 						if (cl == garray_type && param.name == "element_size") {
 							var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
@@ -4450,39 +4483,80 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 				// method can fail
 				current_method_inner_error = true;
 				// add &inner_error before the ellipsis arguments
-				carg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
+				out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
 			}
 
 			if (ellipsis) {
 				/* ensure variable argument list ends with NULL
 				 * except when using printf-style arguments */
 				if (m == null) {
-					carg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
+					in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
 				} else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
-					carg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
+					in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
 				}
 			}
 
 			if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
 				// instance parameter is at the end in a struct creation method
-				carg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
+				out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
+			}
+
+			if (m != null && m.coroutine) {
+				if (expr.is_yield_expression) {
+					// asynchronous call
+					in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
+					in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
+				}
 			}
 
 			// append C arguments in the right order
-			int last_pos = -1;
+
+			int last_pos;
 			int min_pos;
-			while (true) {
-				min_pos = -1;
-				foreach (int pos in carg_map.get_keys ()) {
-					if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
-						min_pos = pos;
+
+			if (async_call != creation_call) {
+				// don't append out arguments for .begin() calls
+				last_pos = -1;
+				while (true) {
+					min_pos = -1;
+					foreach (int pos in out_arg_map.get_keys ()) {
+						if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+							min_pos = pos;
+						}
 					}
+					if (min_pos == -1) {
+						break;
+					}
+					creation_call.add_argument (out_arg_map.get (min_pos));
+					last_pos = min_pos;
 				}
-				if (min_pos == -1) {
-					break;
+			}
+
+			if (async_call != null) {
+				last_pos = -1;
+				while (true) {
+					min_pos = -1;
+					foreach (int pos in in_arg_map.get_keys ()) {
+						if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+							min_pos = pos;
+						}
+					}
+					if (min_pos == -1) {
+						break;
+					}
+					async_call.add_argument (in_arg_map.get (min_pos));
+					last_pos = min_pos;
 				}
-				creation_call.add_argument (carg_map.get (min_pos));
-				last_pos = min_pos;
+			}
+
+			if (expr.is_yield_expression) {
+				// set state before calling async function to support immediate callbacks
+				int state = next_coroutine_state++;
+
+				ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
+				ccode.add_expression (async_call);
+				ccode.add_return (new CCodeConstant ("FALSE"));
+				ccode.add_label ("_state_%d".printf (state));
 			}
 
 			creation_expr = creation_call;
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index bb27040..f164ae1 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -125,10 +125,10 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 		if (m is CreationMethod && m.parent_symbol is Class) {
 			if (context.profile == Profile.GOBJECT) {
 				if (!((Class) m.parent_symbol).is_compact) {
-					ccall.add_argument (new CCodeIdentifier ("object_type"));
+					ccall.add_argument (get_variable_cexpression ("object_type"));
 				}
 			} else {
-				ccall.add_argument (new CCodeIdentifier ("self"));
+				ccall.add_argument (get_this_cexpression ());
 			}
 
 			if (!current_class.is_compact) {
@@ -158,7 +158,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 				}
 			}
 		} else if (m is CreationMethod && m.parent_symbol is Struct) {
-			ccall.add_argument (new CCodeIdentifier ("self"));
+			ccall.add_argument (get_this_cexpression ());
 		} else if (m != null && m.get_type_parameters ().size > 0 && !get_ccode_has_generic_type_parameter (m) && !get_ccode_simple_generics (m) && (ccall != finish_call || expr.is_yield_expression)) {
 			// generic method
 			// don't add generic arguments for .end() calls
@@ -217,7 +217,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 				} else {
 					// Accessing the method from within an instance method
 					var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
-					k.add_argument (new CCodeIdentifier ("self"));
+					k.add_argument (get_this_cexpression ());
 					klass = k;
 				}
 			} else {
@@ -282,12 +282,12 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 			}
 			generate_dynamic_method_wrapper ((DynamicMethod) m);
 		} else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
-			ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, CCodeBaseModule.get_ccode_name (current_class) + "*"));
+			ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, CCodeBaseModule.get_ccode_name (current_class) + "*"));
 
 			if (current_method.body.captured) {
 				// capture self after setting it
 				var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
-				ref_call.add_argument (new CCodeIdentifier ("self"));
+				ref_call.add_argument (get_this_cexpression ());
 
 				ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
 			}
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 24085d2..5559898 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -552,15 +552,17 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 
 				if (m is CreationMethod) {
 					if (in_gobject_creation_method) {
-						ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
+						if (!m.coroutine) {
+							ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
+						}
 					} else if (is_gtypeinstance_creation_method (m)) {
 						var cl = (Class) m.parent_symbol;
 						ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
 
 						if (cl.is_fundamental ()) {
 							var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
-							ccall.add_argument (new CCodeIdentifier ("object_type"));
-							ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
+							ccall.add_argument (get_variable_cexpression ("object_type"));
+							ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
 
 							/* type, dup func, and destroy func fields for generic types */
 							foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
@@ -584,19 +586,21 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 						}
 					} else if (current_type_symbol is Class) {
 						var cl = (Class) m.parent_symbol;
-						ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
+						if (!m.coroutine) {
+							ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
+						}
 
 						if (!((CreationMethod) m).chain_up) {
 							// TODO implicitly chain up to base class as in add_object_creation
 							var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
 							ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
-							ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
+							ccode.add_assignment (get_this_cexpression (), ccall);
 						}
 
 						if (cl.base_class == null) {
 							// derived compact classes do not have fields
 							var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
-							cinitcall.add_argument (new CCodeIdentifier ("self"));
+							cinitcall.add_argument (get_this_cexpression ());
 							ccode.add_expression (cinitcall);
 						}
 					} else {
@@ -714,7 +718,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 						ccode.add_expression (cfreeparams);
 					}
 
-					if (current_type_symbol is Class) {
+					if (current_type_symbol is Class && !m.coroutine) {
 						CCodeExpression cresult = new CCodeIdentifier ("self");
 						if (get_ccode_type (m) != null) {
 							cresult = new CCodeCastExpression (cresult, get_ccode_type (m));
@@ -859,7 +863,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 			cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
 		} else if (m.parent_symbol is Class && m is CreationMethod) {
 			var cl = (Class) m.parent_symbol;
-			if (!cl.is_compact && vcall == null) {
+			if (!cl.is_compact && vcall == null && (direction & 1) == 1) {
 				cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
 			}
 		} else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala
index bee5ceb..05d1e42 100644
--- a/codegen/valagasyncmodule.vala
+++ b/codegen/valagasyncmodule.vala
@@ -32,6 +32,10 @@ public class Vala.GAsyncModule : GSignalModule {
 		data.add_field ("GAsyncResult*", "_res_");
 		data.add_field ("GSimpleAsyncResult*", "_async_result");
 
+		if (m is CreationMethod) {
+			data.add_field ("GType", "object_type");
+		}
+
 		if (m.binding == MemberBinding.INSTANCE) {
 			var type_sym = (TypeSymbol) m.parent_symbol;
 			if (type_sym is ObjectTypeSymbol) {
@@ -205,7 +209,7 @@ public class Vala.GAsyncModule : GSignalModule {
 		var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
 
 		var cl = m.parent_symbol as Class;
-		if (m.binding == MemberBinding.INSTANCE &&
+		if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE &&
 		    cl != null && cl.is_subtype_of (gobject_type)) {
 			var gobject_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
 			gobject_cast.add_argument (new CCodeIdentifier ("self"));
@@ -236,7 +240,9 @@ public class Vala.GAsyncModule : GSignalModule {
 		set_op_res_call.add_argument (new CCodeIdentifier (get_ccode_real_name (m) + "_data_free"));
 		ccode.add_expression (set_op_res_call);
 
-		if (m.binding == MemberBinding.INSTANCE) {
+		if (m is CreationMethod) {
+			ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "object_type"), new CCodeIdentifier ("object_type"));
+		} else if (m.binding == MemberBinding.INSTANCE) {
 			var this_type = m.this_parameter.variable_type.copy ();
 			this_type.value_owned = true;
 
@@ -308,30 +314,62 @@ public class Vala.GAsyncModule : GSignalModule {
 				return;
 			}
 
+			var cl = m.parent_symbol as Class;
+
 			var asyncfunc = new CCodeFunction (get_ccode_name (m), "void");
 			var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
-			cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
-			cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
-
-			generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, null, null, 1);
+			var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
 			if (m.is_private_symbol ()) {
 				asyncfunc.modifiers |= CCodeModifiers.STATIC;
 			}
 
-			decl_space.add_function_declaration (asyncfunc);
+			// do not generate _new functions for creation methods of abstract classes
+			if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
+				generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 1);
+
+				decl_space.add_function_declaration (asyncfunc);
+			}
 
 			var finishfunc = new CCodeFunction (get_ccode_finish_name (m));
 			cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
-			cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
-
-			generate_cparameters (m, decl_space, cparam_map, finishfunc, null, null, null, 2);
+			carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
 			if (m.is_private_symbol ()) {
 				finishfunc.modifiers |= CCodeModifiers.STATIC;
 			}
 
-			decl_space.add_function_declaration (finishfunc);
+			// do not generate _new functions for creation methods of abstract classes
+			if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
+				generate_cparameters (m, decl_space, cparam_map, finishfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 2);
+
+				decl_space.add_function_declaration (finishfunc);
+			}
+
+			if (m is CreationMethod && cl != null) {
+				// _construct function
+				var function = new CCodeFunction (get_ccode_real_name (m));
+
+				if (m.is_private_symbol ()) {
+					function.modifiers |= CCodeModifiers.STATIC;
+				}
+
+				cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+				generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 1);
+
+				decl_space.add_function_declaration (function);
+
+				function = new CCodeFunction (get_ccode_finish_real_name (m));
+
+				if (m.is_private_symbol ()) {
+					function.modifiers |= CCodeModifiers.STATIC;
+				}
+
+				cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+				generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 2);
+
+				decl_space.add_function_declaration (function);
+			}
 		} else {
 			base.generate_method_declaration (m, decl_space);
 		}
@@ -386,6 +424,69 @@ public class Vala.GAsyncModule : GSignalModule {
 		}
 	}
 
+	public override void visit_creation_method (CreationMethod m) {
+		if (!m.coroutine) {
+			base.visit_creation_method (m);
+		} else {
+			push_line (m.source_reference);
+
+			bool visible = !m.is_private_symbol ();
+
+			visit_method (m);
+
+			if (m.source_type == SourceFileType.FAST) {
+				return;
+			}
+
+			// do not generate _new functions for creation methods of abstract classes
+			if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
+				var vfunc = new CCodeFunction (get_ccode_name (m));
+
+				var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+				var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+				push_function (vfunc);
+
+				var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
+				vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
+
+				generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 1);
+				ccode.add_expression (vcall);
+
+				if (!visible) {
+					vfunc.modifiers |= CCodeModifiers.STATIC;
+				}
+
+				pop_function ();
+
+				cfile.add_function (vfunc);
+
+
+				vfunc = new CCodeFunction (get_ccode_finish_name (m));
+
+				cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+				carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+				push_function (vfunc);
+
+				vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
+
+				generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 2);
+				ccode.add_return (vcall);
+
+				if (!visible) {
+					vfunc.modifiers |= CCodeModifiers.STATIC;
+				}
+
+				pop_function ();
+
+				cfile.add_function (vfunc);
+			}
+
+			pop_line ();
+		}
+	}
+
 	void generate_finish_function (Method m) {
 		push_context (new EmitContext ());
 
@@ -406,7 +507,12 @@ public class Vala.GAsyncModule : GSignalModule {
 		push_function (finishfunc);
 
 		var return_type = m.return_type;
-		if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
+		if (m is CreationMethod) {
+			var type_sym = (TypeSymbol) m.parent_symbol;
+			if (type_sym is ObjectTypeSymbol) {
+				ccode.add_declaration (get_ccode_name (type_sym) + "*", new CCodeVariableDeclarator ("result"));
+			}
+		} else if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
 			ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
 		}
 
@@ -443,7 +549,11 @@ public class Vala.GAsyncModule : GSignalModule {
 		}
 		emit_context.pop_symbol ();
 
-		if (return_type.is_real_non_null_struct_type ()) {
+		if (m is CreationMethod) {
+			ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "self"));
+			ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), new CCodeConstant ("NULL"));
+			ccode.add_return (new CCodeIdentifier ("result"));
+		} else if (return_type.is_real_non_null_struct_type ()) {
 			// structs are returned via out parameter
 			CCodeExpression cexpr = new CCodeMemberAccess.pointer (data_var, "result");
 			if (requires_copy (return_type)) {
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index a274de0..d96fb65 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -43,6 +43,8 @@ public class Vala.ObjectCreationExpression : Expression {
 	 */
 	public MemberAccess member_name { get; set; }
 
+	public bool is_yield_expression { get; set; }
+
 	public bool struct_creation { get; set; }
 
 	private List<Expression> argument_list = new ArrayList<Expression> ();
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 099ed07..caecb62 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -978,16 +978,23 @@ public class Vala.Parser : CodeVisitor {
 
 	Expression parse_yield_expression () throws ParseError {
 		expect (TokenType.YIELD);
+
 		var expr = parse_expression ();
 
 		var call = expr as MethodCall;
-		if (call == null) {
+		var object_creation = expr as ObjectCreationExpression;
+		if (call == null && object_creation == null) {
 			Report.error (expr.source_reference, "syntax error, expected method call");
 			throw new ParseError.SYNTAX ("expected method call");
 		}
 
-		call.is_yield_expression = true;
-		return call;
+		if (call != null) {
+			call.is_yield_expression = true;
+		} else if (object_creation != null) {
+			object_creation.is_yield_expression = true;
+		}
+
+		return expr;
 	}
 
 	Expression parse_sizeof_expression () throws ParseError {



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