[vala/wip/transform: 36/50] Move ForeachStatement transformation into the code transformer
- From: Luca Bruno <lucabru src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/transform: 36/50] Move ForeachStatement transformation into the code transformer
- Date: Fri, 13 Apr 2012 13:10:16 +0000 (UTC)
commit e934838b257ae37a8c9ae5ef3af9d4cbe8121774
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 9a64c1d..68b9363 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]