[vala/wip/transform: 235/273] Move ForeachStatement transformation into the code transformer



commit dc79960771cf54a9fd474ff1099f0ed614b65d17
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/valaccodebasemodule.vala        |    4 +-
 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          |  165 ++++++++++---------------------
 vala/valaobjectcreationexpression.vala  |    4 +-
 vala/valasemanticanalyzer.vala          |    8 --
 11 files changed, 137 insertions(+), 274 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index a359e39..43cd964 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1971,7 +1971,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                }
                        } else if (b.parent_symbol is ForeachStatement) {
                                var stmt = (ForeachStatement) b.parent_symbol;
-                               if (!stmt.use_iterator && stmt.element_variable.captured) {
+                               if (stmt.element_variable.captured) {
                                        ccode.add_assignment (new CCodeMemberAccess.pointer 
(get_variable_cexpression ("_data%d_".printf (block_id)), get_local_cname (stmt.element_variable)), 
get_variable_cexpression (get_local_cname (stmt.element_variable)));
                                }
                        }
@@ -2271,7 +2271,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                var block = local.parent_symbol;
                if (block != null) {
                        var stmt = block.parent_symbol as ForeachStatement;
-                       if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
+                       if (stmt != null && stmt.element_variable == local) {
                                return true;
                        }
                }
diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala
index 91268e7..8646f26 100644
--- a/codegen/valaccodecontrolflowmodule.vala
+++ b/codegen/valaccodecontrolflowmodule.vala
@@ -213,137 +213,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 f8f882c..8edd2f4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -63,6 +63,7 @@ TESTS = \
        control-flow/foreach.vala \
        control-flow/switch.vala \
        control-flow/sideeffects.vala \
+       control-flow/bug628336.vala \
        control-flow/bug639482.vala \
        control-flow/bug652549.vala \
        control-flow/bug661985.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 c7fd318..70721b8 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 7f69976..e039907 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) {
@@ -426,7 +484,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);
 
                                var temp_access = SemanticAnalyzer.create_temp_access (local, 
expr.target_type);
 
@@ -439,7 +497,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);
@@ -453,7 +511,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);
@@ -465,7 +523,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 ebe489f..bbdcb45 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 (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 (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 (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 6404cdc..25b6a20 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -414,7 +414,7 @@ public class Vala.ObjectCreationExpression : Expression {
                                var local = new LocalVariable (value_type, get_temp_name (), null, 
source_reference);
                                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);
 
                                // don't set initializer earlier as this changes parent_node and 
parent_statement
                                local.initializer = this;
@@ -427,7 +427,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 835f9b4..8d4d7b3 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -226,14 +226,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]