[vala/staging: 36/45] Move ForeachStatement transformation into the code transformer



commit 1b88f66f532e50aea9289dbedae64ade54d6cc15
Author: Luca Bruno <lucabru src gnome org>
Date:   Wed Jan 4 18:38:38 2012 +0100

    Move ForeachStatement transformation into the code transformer
    
    Fixes bug 628336.

 codegen/valaccodecontrolflowmodule.vala |  131 ------------------------
 tests/Makefile.am                       |    1 +
 tests/control-flow/bug628336.vala       |    8 ++
 vala/valaassignment.vala                |    2 +-
 vala/valabinaryexpression.vala          |    2 +-
 vala/valacodebuilder.vala               |   18 ++--
 vala/valacodetransformer.vala           |   68 ++++++++++++-
 vala/valaforeachstatement.vala          |  167 ++++++++++---------------------
 vala/valaobjectcreationexpression.vala  |    4 +-
 vala/valasemanticanalyzer.vala          |    8 --
 10 files changed, 136 insertions(+), 273 deletions(-)
---
diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala
index 5a4c297..739f4c4 100644
--- a/codegen/valaccodecontrolflowmodule.vala
+++ b/codegen/valaccodecontrolflowmodule.vala
@@ -218,137 +218,6 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule {
 		ccode.close ();
 	}
 
-	public override void visit_foreach_statement (ForeachStatement stmt) {
-		ccode.open_block ();
-
-		var collection_backup = stmt.collection_variable;
-		var collection_type = collection_backup.variable_type;
-
-		var array_type = collection_type as ArrayType;
-		if (array_type != null) {
-			// avoid assignment issues
-			array_type.inline_allocated = false;
-			array_type.fixed_length = false;
-		}
-
-		visit_local_variable (collection_backup);
-		ccode.add_assignment (get_variable_cexpression (get_local_cname (collection_backup)), get_cvalue (stmt.collection));
-		
-		if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
-			// exception handling
-			add_simple_check (stmt.collection);
-		}
-
-		if (stmt.collection.value_type is ArrayType) {
-			array_type = (ArrayType) stmt.collection.value_type;
-
-			var array_len = get_array_length_cexpression (stmt.collection);
-
-			// store array length for use by _vala_array_free
-			ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_local_cname (collection_backup), 1)), array_len);
-
-			var iterator_variable = new LocalVariable (int_type.copy (), stmt.variable_name + "_it");
-			visit_local_variable (iterator_variable);
-			var it_name = get_local_cname (iterator_variable);
-		
-			var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (it_name), array_len);
-
-			ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeConstant ("0")),
-			                   ccond,
-			                   new CCodeAssignment (get_variable_cexpression (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (it_name), new CCodeConstant ("1"))));
-
-			CCodeExpression element_expr = new CCodeElementAccess (get_variable_cexpression (get_local_cname (collection_backup)), get_variable_cexpression (it_name));
-
-			var element_type = array_type.element_type.copy ();
-			element_type.value_owned = false;
-			element_expr = get_cvalue_ (transform_value (new GLibValue (element_type, element_expr, true), stmt.type_reference, stmt));
-
-			visit_local_variable (stmt.element_variable);
-			ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
-
-			// set array length for stacked arrays
-			if (stmt.type_reference is ArrayType) {
-				var inner_array_type = (ArrayType) stmt.type_reference;
-				for (int dim = 1; dim <= inner_array_type.rank; dim++) {
-					ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_local_cname (stmt.element_variable), dim)), new CCodeConstant ("-1"));
-				}
-			}
-
-			stmt.body.emit (this);
-
-			ccode.close ();
-		} else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
-			// iterating over a GList or GSList
-
-			var iterator_variable = new LocalVariable (collection_type.copy (), stmt.variable_name + "_it");
-			visit_local_variable (iterator_variable);
-			var it_name = get_local_cname (iterator_variable);
-			
-			var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (it_name), new CCodeConstant ("NULL"));
-
-			ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (get_local_cname (collection_backup))),
-							ccond,
-							new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next")));
-
-			CCodeExpression element_expr = new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "data");
-
-			if (collection_type.get_type_arguments ().size != 1) {
-				Report.error (stmt.source_reference, "internal error: missing generic type argument");
-				stmt.error = true;
-				return;
-			}
-
-			var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
-			element_data_type.value_owned = false;
-			element_expr = convert_from_generic_pointer (element_expr, element_data_type);
-			element_expr = get_cvalue_ (transform_value (new GLibValue (element_data_type, element_expr), stmt.type_reference, stmt));
-
-			visit_local_variable (stmt.element_variable);
-			ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
-
-			stmt.body.emit (this);
-
-			ccode.close ();
-		} else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
-			// iterating over a GValueArray
-
-			var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
-			visit_local_variable (iterator_variable);
-			var arr_index = get_variable_cname (get_local_cname (iterator_variable));
-
-			var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (get_local_cname (collection_backup)), "n_values"));
-
-			ccode.open_for (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")),
-			                   ccond,
-			                   new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
-
-			var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth"));
-			get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
-			get_item.add_argument (get_variable_cexpression (arr_index));
-
-			CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item);
-
-			if (stmt.type_reference.value_owned) {
-				element_expr = get_cvalue_ (copy_value (new GLibValue (stmt.type_reference, element_expr), new StructValueType (gvalue_type)));
-			}
-
-			visit_local_variable (stmt.element_variable);
-			ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
-
-			stmt.body.emit (this);
-
-			ccode.close ();
-		}
-
-		foreach (LocalVariable local in stmt.get_local_variables ()) {
-			if (requires_destroy (local.variable_type)) {
-				ccode.add_expression (destroy_local (local));
-			}
-		}
-
-		ccode.close ();
-	}
-
 	public override void visit_break_statement (BreakStatement stmt) {
 		append_local_free (current_symbol, true);
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 119f1f8..7dd723c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -58,6 +58,7 @@ TESTS = \
 	control-flow/foreach.vala \
 	control-flow/switch.vala \
 	control-flow/sideeffects.vala \
+	control-flow/bug628336.vala \
 	control-flow/bug652549.vala \
 	control-flow/bug665904.vala \
 	enums/enums.vala \
diff --git a/tests/control-flow/bug628336.vala b/tests/control-flow/bug628336.vala
new file mode 100644
index 0000000..86ac154
--- /dev/null
+++ b/tests/control-flow/bug628336.vala
@@ -0,0 +1,8 @@
+void main () {
+	var foo = new string[]{"bar", "bar"};
+	foreach (string bar in foo) {
+		assert (bar == "bar");
+		SourceFunc f = () => bar == "bar";
+		assert (f ());
+	}
+}
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
index 93dbb25..f5ba935 100644
--- a/vala/valaassignment.vala
+++ b/vala/valaassignment.vala
@@ -130,7 +130,7 @@ public class Vala.Assignment : Expression {
 
 		checked = true;
 
-		var insert_block = context.analyzer.get_insert_block (this);
+		var insert_block = context.analyzer.get_current_block (this);
 
 		if (left is Tuple && operator == AssignmentOperator.SIMPLE && parent_node is ExpressionStatement) {
 			var tuple = (Tuple) left;
diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala
index 415bde2..0edefb9 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -148,7 +148,7 @@ public class Vala.BinaryExpression : Expression {
 
 		checked = true;
 
-		var insert_block = context.analyzer.get_insert_block (this);
+		var insert_block = context.analyzer.get_current_block (this);
 
 		// some expressions are not in a block,
 		// for example, expressions in method contracts
diff --git a/vala/valacodebuilder.vala b/vala/valacodebuilder.vala
index 19e3590..300c69f 100644
--- a/vala/valacodebuilder.vala
+++ b/vala/valacodebuilder.vala
@@ -27,19 +27,16 @@ public class Vala.CodeBuilder {
 	public Statement insert_statement;
 	public Block insert_block;
 	public ArrayList<Statement> statement_stack = new ArrayList<Statement> ();
-	public ArrayList<CodeNode> check_nodes = new ArrayList<CodeNode> ();
+	public ArrayList<CodeNode> decl_nodes = new ArrayList<CodeNode> ();
 	public SourceReference source_reference;
 
 	public CodeBuilder (CodeContext context, Statement insert_statement, SourceReference source_reference) {
-		current_block = new Block (source_reference);
-		insert_statement = insert_statement;
-		insert_block = context.analyzer.get_insert_block (insert_statement);
 		this.source_reference = source_reference;
 
-		var statement_block = context.analyzer.get_current_block (insert_statement);
-		statement_block.insert_before (insert_statement, current_block);
-		insert_statement = current_block;
-		check_nodes.add (current_block);
+		current_block = new Block (source_reference);
+		insert_block = context.analyzer.get_current_block (insert_statement);
+		insert_block.insert_before (insert_statement, current_block);
+		this.insert_statement = current_block;
 	}
 
 	public CodeBuilder.for_subroutine (Subroutine m) {
@@ -50,9 +47,10 @@ public class Vala.CodeBuilder {
 	}
 
 	public void check (CodeTransformer transformer) {
-		foreach (var node in check_nodes) {
+		foreach (var node in decl_nodes) {
 			transformer.check (node);
 		}
+		transformer.check (current_block);
 	}
 
 	public void open_block () {
@@ -227,7 +225,7 @@ public class Vala.CodeBuilder {
 		var local = new LocalVariable (type, CodeNode.get_temp_name (), initializer, source_reference);
 		var stmt = new DeclarationStatement (local, source_reference);
 		insert_block.insert_before (insert_statement, stmt);
-		check_nodes.insert (0, stmt);
+		decl_nodes.add (stmt);
 		return local.name;
 	}
 
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
index 6ee1e77..09331db 100644
--- a/vala/valacodetransformer.vala
+++ b/vala/valacodetransformer.vala
@@ -365,7 +365,65 @@ public class Vala.CodeTransformer : CodeVisitor {
 	}
 
 	public override void visit_foreach_statement (ForeachStatement stmt) {
-		stmt.accept_children (this);
+		push_builder (new CodeBuilder (context, stmt, stmt.source_reference));
+		var collection = b.add_temp_declaration (stmt.collection.value_type, stmt.collection);
+
+		stmt.body.remove_local_variable (stmt.element_variable);
+		stmt.element_variable.checked = false;
+		var decl = new DeclarationStatement (stmt.element_variable, stmt.element_variable.source_reference);
+
+		switch (stmt.foreach_iteration) {
+		case ForeachIteration.ARRAY:
+		case ForeachIteration.GVALUE_ARRAY:
+			// array or GValueArray
+			var array = collection;
+			if (stmt.foreach_iteration == ForeachIteration.GVALUE_ARRAY) {
+				array = collection+".values";
+			}
+			var i = b.add_temp_declaration (null, expression ("0"));
+			b.open_for (null, expression (@"$i < $array.length"), expression (@"$i++"));
+			stmt.element_variable.initializer = expression (@"$array[$i]");
+			break;
+		case ForeachIteration.GLIST:
+			// GList or GSList
+			b.open_for (null, expression (@"$collection != null"), expression (@"$collection = $collection.next"));
+			stmt.element_variable.initializer = expression (@"$collection.data");
+			break;
+		case ForeachIteration.INDEX:
+			// get()+size
+			var size = b.add_temp_declaration (null, expression ("$collection.size"));
+			var i = b.add_temp_declaration (null, expression ("0"));
+			b.open_for (null, expression (@"$i < $size"), expression (@"$i++"));
+			stmt.element_variable.initializer = expression (@"$collection.get ($i)");
+			break;
+		case ForeachIteration.NEXT_VALUE:
+			// iterator+next_value()
+			var iterator = b.add_temp_declaration (null, expression (@"$collection.iterator ()"));
+			var temp = b.add_temp_declaration (stmt.type_reference);
+			b.open_while (expression (@"($temp = $iterator.next_value ()) != null"));
+			stmt.element_variable.initializer = expression (temp);
+			break;
+		case ForeachIteration.NEXT_GET:
+			// iterator+next()+get()
+			var iterator = b.add_temp_declaration (null, expression (@"$collection.iterator ()"));
+			b.open_while (expression (@"$iterator.next ()"));
+			stmt.element_variable.initializer = expression (@"$iterator.get ()");
+			break;
+		default:
+			assert_not_reached ();
+		}
+
+		stmt.body.insert_statement (0, decl);
+		b.add_statement (stmt.body);
+		b.close ();
+
+		var parent_block = context.analyzer.get_current_block (stmt);
+		context.analyzer.replaced_nodes.add (stmt);
+		parent_block.replace_statement (stmt, new EmptyStatement (stmt.source_reference));
+
+		stmt.body.checked = false;
+		b.check (this);
+		pop_builder ();
 	}
 
 	public override void visit_break_statement (BreakStatement stmt) {
@@ -430,7 +488,7 @@ public class Vala.CodeTransformer : CodeVisitor {
 				local.floating = true;
 				var decl = new DeclarationStatement (local, expr.source_reference);
 
-				expr.insert_statement (context.analyzer.get_insert_block (expr), decl);
+				expr.insert_statement (context.analyzer.get_current_block (expr), decl);
 
 				Expression temp_access = new MemberAccess.simple (local.name, expr.source_reference);
 				temp_access.target_type = expr.target_type;
@@ -444,7 +502,7 @@ public class Vala.CodeTransformer : CodeVisitor {
 				// otherwise there will be scoping issues in the
 				var block = context.analyzer.get_current_block (expr);
 				block.remove_local_variable (local);
-				context.analyzer.get_insert_block (expr).add_local_variable (local);
+				context.analyzer.get_current_block (expr).add_local_variable (local);
 
 				context.analyzer.replaced_nodes.add (expr);
 				old_parent_node.replace_expression (expr, temp_access);
@@ -458,7 +516,7 @@ public class Vala.CodeTransformer : CodeVisitor {
 
 		var local = new LocalVariable (expr.value_type, expr.get_temp_name (), null, expr.source_reference);
 		var decl = new DeclarationStatement (local, expr.source_reference);
-		expr.insert_statement (context.analyzer.get_insert_block (expr), decl);
+		expr.insert_statement (context.analyzer.get_current_block (expr), decl);
 		check (decl);
 
 		var true_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, expr.true_expression.source_reference), expr.true_expression, AssignmentOperator.SIMPLE, expr.true_expression.source_reference), expr.true_expression.source_reference);
@@ -470,7 +528,7 @@ public class Vala.CodeTransformer : CodeVisitor {
 		false_block.add_statement (false_stmt);
 
 		var if_stmt = new IfStatement (expr.condition, true_block, false_block, expr.source_reference);
-		expr.insert_statement (context.analyzer.get_insert_block (expr), if_stmt);
+		expr.insert_statement (context.analyzer.get_current_block (expr), if_stmt);
 		check (if_stmt);
 
 		var ma = new MemberAccess.simple (local.name, expr.source_reference);
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
index 3195159..590a1b3 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -25,7 +25,7 @@
  * Represents a foreach statement in the source code. Foreach statements iterate
  * over the elements of a collection.
  */
-public class Vala.ForeachStatement : Block {
+public class Vala.ForeachStatement : CodeNode, Statement {
 	/**
 	 * Specifies the element type.
 	 */
@@ -70,22 +70,15 @@ public class Vala.ForeachStatement : Block {
 		}
 	}
 
-	public bool use_iterator { get; private set; }
-
-	/**
-	 * Specifies the declarator for the generated element variable.
-	 */
-	public LocalVariable element_variable { get; set; }
-
 	/**
-	 * Specifies the declarator for the generated collection variable.
+	 * Specifies the approach used for the iteration.
 	 */
-	public LocalVariable collection_variable { get; set; }
+	public ForeachIteration foreach_iteration { get; private set; }
 
 	/**
-	 * Specifies the declarator for the generated iterator variable.
+	 * Specifies the declarator for the generated element variable.
 	 */
-	public LocalVariable iterator_variable { get; set; }
+	public LocalVariable element_variable { get; set; }
 
 	private Expression _collection;
 	private Block _body;
@@ -102,28 +95,18 @@ public class Vala.ForeachStatement : Block {
 	 * @return       newly created foreach statement
 	 */
 	public ForeachStatement (DataType? type_reference, string variable_name, Expression collection, Block body, SourceReference source_reference) {
-		base (source_reference);
 		this.variable_name = variable_name;
 		this.collection = collection;
 		this.body = body;
 		this.type_reference = type_reference;
+		this.source_reference = source_reference;
 	}
 	
 	public override void accept (CodeVisitor visitor) {
-		if (use_iterator) {
-			base.accept (visitor);
-			return;
-		}
-
 		visitor.visit_foreach_statement (this);
 	}
 
 	public override void accept_children (CodeVisitor visitor) {
-		if (use_iterator) {
-			base.accept_children (visitor);
-			return;
-		}
-
 		collection.accept (visitor);
 		visitor.visit_end_full_expression (collection);
 
@@ -153,8 +136,6 @@ public class Vala.ForeachStatement : Block {
 
 		checked = true;
 
-		owner = context.analyzer.get_current_symbol (parent_node).scope;
-
 		// analyze collection expression first, used for type inference
 		if (!collection.check (context)) {
 			// ignore inner error
@@ -168,14 +149,15 @@ public class Vala.ForeachStatement : Block {
 
 		var collection_type = collection.value_type.copy ();
 		collection.target_type = collection_type.copy ();
-		
-		if (context.profile != Profile.DOVA && collection_type.is_array ()) {
+
+		if (collection_type.is_array ()) {
 			var array_type = (ArrayType) collection_type;
 
 			// can't use inline-allocated array for temporary variable
 			array_type.inline_allocated = false;
 
-			return check_without_iterator (context, collection_type, array_type.element_type);
+			foreach_iteration = ForeachIteration.ARRAY;
+			error = !analyze_element_type (array_type.element_type);
 		} else if (context.profile == Profile.GOBJECT && (collection_type.compatible (context.analyzer.glist_type) || collection_type.compatible (context.analyzer.gslist_type))) {
 			if (collection_type.get_type_arguments ().size != 1) {
 				error = true;
@@ -183,12 +165,25 @@ public class Vala.ForeachStatement : Block {
 				return false;
 			}
 
-			return check_without_iterator (context, collection_type, collection_type.get_type_arguments ().get (0));
+			foreach_iteration = ForeachIteration.GLIST;
+			error = !analyze_element_type (collection_type.get_type_arguments ().get (0));
 		} else if (context.profile == Profile.GOBJECT && collection_type.compatible (context.analyzer.gvaluearray_type)) {
-			return check_without_iterator (context, collection_type, context.analyzer.gvalue_type);
+			foreach_iteration = ForeachIteration.GVALUE_ARRAY;
+			error = !analyze_element_type (context.analyzer.gvalue_type);
 		} else {
-			return check_with_iterator (context, collection_type);
+			error = !check_with_iterator (context, collection_type);
 		}
+
+		element_variable = new LocalVariable (type_reference, variable_name, null, source_reference);
+		element_variable.checked = true;
+		element_variable.active = true;
+		body.add_local_variable (element_variable);
+		if (!body.check (context)) {
+			error = true;
+		}
+		element_variable.active = false;
+
+		return !error;
 	}
 
 	bool check_with_index (CodeContext context, DataType collection_type) {
@@ -199,30 +194,27 @@ public class Vala.ForeachStatement : Block {
 		if (get_method.get_parameters ().size != 1) {
 			return false;
 		}
-		var size_property = collection_type.get_member ("size") as Property;
-		if (size_property == null) {
+		var element_type = get_method.return_type.get_actual_type (collection.value_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;
 			return false;
 		}
 
-		add_statement (new DeclarationStatement (new LocalVariable (null, "_%s_list".printf (variable_name), collection, source_reference), source_reference));
-		add_statement (new DeclarationStatement (new LocalVariable (null, "_%s_size".printf (variable_name), new MemberAccess (new MemberAccess.simple ("_%s_list".printf (variable_name), source_reference), "size", source_reference), source_reference), source_reference));
-		add_statement (new DeclarationStatement (new LocalVariable (null, "_%s_index".printf (variable_name), new UnaryExpression (UnaryOperator.MINUS, new IntegerLiteral ("1", source_reference), source_reference), source_reference), source_reference));
-		var next = new UnaryExpression (UnaryOperator.INCREMENT, new MemberAccess.simple ("_%s_index".printf (variable_name), source_reference), source_reference);
-		var conditional = new BinaryExpression (BinaryOperator.LESS_THAN, next, new MemberAccess.simple ("_%s_size".printf (variable_name), source_reference), source_reference);
-		var loop = new WhileStatement (conditional, body, source_reference);
-		add_statement (loop);
+		if (!analyze_element_type (element_type)) {
+			return false;
+		}
 
-		var get_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_list".printf (variable_name), source_reference), "get", source_reference), source_reference);
-		get_call.add_argument (new MemberAccess.simple ("_%s_index".printf (variable_name), source_reference));
-		body.insert_statement (0, new DeclarationStatement (new LocalVariable (type_reference, variable_name, get_call, source_reference), source_reference));
+		var size_property = collection_type.get_member ("size") as Property;
+		if (size_property == null) {
+			return false;
+		}
 
-		checked = false;
-		return base.check (context);
+		foreach_iteration = ForeachIteration.INDEX;
+		return true;
 	}
 
 	bool check_with_iterator (CodeContext context, DataType collection_type) {
-		use_iterator = true;
-
 		if (check_with_index (context, collection_type)) {
 			return true;
 		}
@@ -245,9 +237,6 @@ public class Vala.ForeachStatement : Block {
 			return false;
 		}
 
-		var iterator_call = new MethodCall (new MemberAccess (collection, "iterator", source_reference), source_reference);
-		add_statement (new DeclarationStatement (new LocalVariable (iterator_type, "_%s_it".printf (variable_name), iterator_call, source_reference), source_reference));
-
 		var next_value_method = iterator_type.get_member ("next_value") as Method;
 		var next_method = iterator_type.get_member ("next") as Method;
 		if (next_value_method != null) {
@@ -267,13 +256,7 @@ public class Vala.ForeachStatement : Block {
 				return false;
 			}
 
-			add_statement (new DeclarationStatement (new LocalVariable (type_reference, variable_name, null, source_reference), source_reference));
-
-			var next_value_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "next_value", source_reference), source_reference);
-			var assignment = new Assignment (new MemberAccess (null, variable_name, source_reference), next_value_call, AssignmentOperator.SIMPLE, source_reference);
-			var conditional = new BinaryExpression (BinaryOperator.INEQUALITY, assignment, new NullLiteral (source_reference), source_reference);
-			var loop = new WhileStatement (conditional, body, source_reference);
-			add_statement (loop);
+			foreach_iteration = ForeachIteration.NEXT_VALUE;
 		} else if (next_method != null) {
 			if (next_method.get_parameters ().size != 0) {
 				Report.error (collection.source_reference, "`%s' must not have any parameters".printf (next_method.get_full_name ()));
@@ -307,20 +290,10 @@ public class Vala.ForeachStatement : Block {
 				return false;
 			}
 
-			var next_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "next", source_reference), source_reference);
-			var loop = new WhileStatement (next_call, body, source_reference);
-			add_statement (loop);
-
-			var get_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "get", source_reference), source_reference);
-			body.insert_statement (0, new DeclarationStatement (new LocalVariable (type_reference, variable_name, get_call, source_reference), source_reference));
-		} else {
-			Report.error (collection.source_reference, "`%s' does not have a `next_value' or `next' method".printf (iterator_type.to_string ()));
-			error = true;
-			return false;
+			foreach_iteration = ForeachIteration.NEXT_GET;
 		}
 
-		checked = false;
-		return base.check (context);
+		return true;
 	}
 
 	bool analyze_element_type (DataType element_type) {
@@ -341,41 +314,6 @@ public class Vala.ForeachStatement : Block {
 		return true;
 	}
 
-	bool check_without_iterator (CodeContext context, DataType collection_type, DataType element_type) {
-		// analyze element type
-		if (type_reference == null) {
-			// var type
-			type_reference = element_type.copy ();
-		} else if (!element_type.compatible (type_reference)) {
-			error = true;
-			Report.error (source_reference, "Foreach: Cannot convert from `%s' to `%s'".printf (element_type.to_string (), type_reference.to_string ()));
-			return false;
-		}
-
-		element_variable = new LocalVariable (type_reference, variable_name, null, source_reference);
-
-		body.add_local_variable (element_variable);
-		element_variable.active = true;
-		element_variable.checked = true;
-
-		// call add_local_variable to check for shadowed variable
-		add_local_variable (element_variable);
-		remove_local_variable (element_variable);
-
-		body.check (context);
-
-		foreach (LocalVariable local in get_local_variables ()) {
-			local.active = false;
-		}
-
-		collection_variable = new LocalVariable (collection_type.copy (), "%s_collection".printf (variable_name));
-
-		add_local_variable (collection_variable);
-		collection_variable.active = true;
-
-		return !error;
-	}
-
 	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
 		if (source_reference == null) {
 			source_reference = this.source_reference;
@@ -385,20 +323,9 @@ public class Vala.ForeachStatement : Block {
 	}
 
 	public override void emit (CodeGenerator codegen) {
-		if (use_iterator) {
-			base.emit (codegen);
-			return;
-		}
-
 		collection.emit (codegen);
 		codegen.visit_end_full_expression (collection);
 
-		element_variable.active = true;
-		collection_variable.active = true;
-		if (iterator_variable != null) {
-			iterator_variable.active = true;
-		}
-
 		codegen.visit_foreach_statement (this);
 	}
 
@@ -406,3 +333,13 @@ public class Vala.ForeachStatement : Block {
 		collection.add (element_variable);
 	}
 }
+
+public enum Vala.ForeachIteration {
+	NONE,
+		ARRAY,
+		GVALUE_ARRAY,
+		GLIST,
+		INDEX,
+		NEXT_VALUE,
+		NEXT_GET
+}
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index 422af04..1c37218 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -403,7 +403,7 @@ public class Vala.ObjectCreationExpression : Expression {
 				local.floating = true;
 				var decl = new DeclarationStatement (local, source_reference);
 
-				insert_statement (context.analyzer.get_insert_block (this), decl);
+				insert_statement (context.analyzer.get_current_block (this), decl);
 
 				Expression temp_access = new MemberAccess.simple (local.name, source_reference);
 				temp_access.target_type = target_type;
@@ -417,7 +417,7 @@ public class Vala.ObjectCreationExpression : Expression {
 				// otherwise there will be scoping issues in the
 				var block = context.analyzer.get_current_block (this);
 				block.remove_local_variable (local);
-				context.analyzer.get_insert_block (this).add_local_variable (local);
+				context.analyzer.get_current_block (this).add_local_variable (local);
 
 				old_parent_node.replace_expression (this, temp_access);
 				temp_access.check (context);
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 198b074..6aed71f 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -238,14 +238,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 		return get_current_symbol (node) as Block;
 	}
 
-	public unowned Block? get_insert_block (CodeNode node) {
-		unowned Block? block = get_current_block (node);
-		if (block is ForeachStatement) {
-			block = block.parent_symbol as Block;
-		}
-		return block;
-	}
-
 	// check whether type is at least as accessible as the specified symbol
 	public bool is_type_accessible (Symbol sym, DataType type) {
 		return type.is_accessible (sym);



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