Version 1.9.0-dev.10.11
svn merge -c 44558 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44559 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44592 https://dart.googlecode.com/svn/branches/bleeding_edge trunk (mf conflict resolution for ast_printer.cc)
git-svn-id: http://dart.googlecode.com/svn/trunk@44593 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 8e900c0..83611e2 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -749,7 +749,12 @@
js.Expression leftHandSide = node.leftHandSide;
if (leftHandSide is js.VariableUse) {
return withExpression(node.value, (js.Expression value) {
- return new js.Assignment(leftHandSide, value);
+ // A non-compound [js.Assignment] has `op==null`. So it works out to
+ // use [js.Assignment.compound] for all cases.
+ // Visit the [js.VariableUse] to ensure renaming is done correctly.
+ return new js.Assignment.compound(visitExpression(leftHandSide),
+ node.op,
+ value);
}, store: false);
} else if (leftHandSide is js.PropertyAccess) {
return withExpressions([
@@ -1211,7 +1216,7 @@
if (node.op == "++" || node.op == "--") {
js.Expression argument = node.argument;
if (argument is js.VariableUse) {
- return new js.Postfix(node.op, argument);
+ return new js.Postfix(node.op, visitExpression(argument));
} else if (argument is js.PropertyAccess) {
return withExpression2(argument.receiver, argument.selector,
(receiver, selector) {
@@ -1233,7 +1238,7 @@
if (node.op == "++" || node.op == "--") {
js.Expression argument = node.argument;
if (argument is js.VariableUse) {
- return new js.Prefix(node.op, argument);
+ return new js.Prefix(node.op, visitExpression(argument));
} else if (argument is js.PropertyAccess) {
return withExpression2(argument.receiver, argument.selector,
(receiver, selector) {
@@ -1528,7 +1533,7 @@
@override
js.Expression visitVariableDeclarationList(js.VariableDeclarationList node) {
- List<js.Assignment> initializations = new List<js.Assignment>();
+ List<js.Expression> initializations = new List<js.Expression>();
// Declaration of local variables is hoisted outside the helper but the
// initialization is done here.
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 18db66c..7c8293e 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -611,6 +611,7 @@
Assignment(leftHandSide, value)
: this.compound(leftHandSide, null, value);
+ // If `this.op == null` this will be a non-compound assignment.
Assignment.compound(this.leftHandSide, this.op, this.value);
int get precedenceLevel => ASSIGNMENT;
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index e175da5..fdbe56a 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -3782,7 +3782,10 @@
Bind(new(I) AllocateContextInstr(node->token_pos(),
num_context_variables));
{ LocalVariable* tmp_var = EnterTempLocalScope(allocated_context);
- if (HasContextScope() || !is_top_level_sequence) {
+ if (!is_top_level_sequence || HasContextScope()) {
+ ASSERT(is_top_level_sequence ||
+ (nested_block.ContextLevel() ==
+ nested_block.outer()->ContextLevel() + 1));
Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var));
Value* parent_context = Bind(BuildCurrentContext());
Do(new(I) StoreInstanceFieldInstr(Context::parent_offset(),
@@ -3991,7 +3994,7 @@
if (is_open() &&
(num_context_variables > 0) &&
- (HasContextScope() || !is_top_level_sequence)) {
+ (!is_top_level_sequence || HasContextScope())) {
UnchainContexts(1);
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index df9a50c..6bf6b45 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2473,17 +2473,13 @@
const int first_parameter_index = 0;
const int num_parameters = 0;
const int first_frame_index = -1;
- LocalScope* loop_owner = parent_scope;
- LocalScope* context_owner = NULL; // No context allocated yet.
bool found_captured_vars = false;
int next_frame_index = parent_scope->AllocateVariables(first_parameter_index,
num_parameters,
first_frame_index,
- loop_owner,
- &context_owner,
+ NULL,
&found_captured_vars);
EXPECT_EQ(first_frame_index, next_frame_index); // a and c not in frame.
- EXPECT_EQ(parent_scope, context_owner); // parent_scope allocated a context.
const intptr_t parent_scope_context_level = 1;
EXPECT_EQ(parent_scope_context_level, parent_scope->context_level());
EXPECT(found_captured_vars);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 7103b61..4f8be44 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -220,14 +220,12 @@
// Allocate parameters and local variables, either in the local frame or
// in the context(s).
- LocalScope* context_owner = NULL; // No context needed yet.
bool found_captured_variables = false;
int next_free_frame_index =
scope->AllocateVariables(first_parameter_index_,
num_params,
first_stack_local_index_,
- scope,
- &context_owner,
+ NULL,
&found_captured_variables);
// Frame indices are relative to the frame pointer and are decreasing.
@@ -9411,7 +9409,7 @@
// restore saved_try_context
SequenceNode* true_branch =
- new(Z) SequenceNode(Scanner::kNoSourcePos, current_block_->scope);
+ new(Z) SequenceNode(Scanner::kNoSourcePos, NULL);
AstNode* return_from_generator = new(Z) ReturnNode(yield_pos);
true_branch->Add(return_from_generator);
AddNodeForFinallyInlining(return_from_generator);
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index ca7a261..b2819b0 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -277,9 +277,9 @@
// function main uses one ctx var at (1); saves caller ctx.
"main\n"
- " 0 ContextLevel level=1 scope=1 begin=2 end=37\n"
- " 1 CurrentCtx scope=0 begin=0 end=0"
+ " 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
+ " 1 ContextLevel level=1 scope=2 begin=4 end=37\n"
" 2 ContextVar level=1 begin=10 end=37 name=value\n"
" 3 StackVar scope=2 begin=12 end=37 name=f\n",
CaptureVarsAtLine(lib, "main", 4));
@@ -318,9 +318,9 @@
// happens here and not in the outermost function. We always
// save the entry context at the last possible moment.
"a.b\n"
- " 0 ContextLevel level=1 scope=1 begin=8 end=38\n"
- " 1 CurrentCtx scope=0 begin=0 end=0"
+ " 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
+ " 1 ContextLevel level=1 scope=2 begin=10 end=38\n"
" 2 ContextVar level=1 begin=16 end=38 name=value\n"
" 3 StackVar scope=2 begin=18 end=38 name=c\n"
@@ -377,9 +377,9 @@
// of chaining from b. This keeps us from holding onto closures
// that we would never access.
"a.b.aa\n"
- " 0 ContextLevel level=1 scope=1 begin=20 end=50\n"
- " 1 CurrentCtx scope=0 begin=0 end=0"
+ " 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
+ " 1 ContextLevel level=1 scope=2 begin=22 end=50\n"
" 2 ContextVar level=1 begin=28 end=50 name=value2\n"
" 3 StackVar scope=2 begin=30 end=50 name=bb\n"
@@ -404,9 +404,9 @@
// a shares value1, saves entry ctx.
"a\n"
- " 0 ContextLevel level=1 scope=1 begin=2 end=68\n"
- " 1 CurrentCtx scope=0 begin=0 end=0"
+ " 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
+ " 1 ContextLevel level=1 scope=2 begin=4 end=68\n"
" 2 ContextVar level=1 begin=10 end=68 name=value1\n"
" 3 StackVar scope=2 begin=12 end=68 name=b\n",
CaptureVarsAtLine(lib, "a", 7));
@@ -557,9 +557,9 @@
" name=:current_context_var\n"
"a\n"
- " 0 ContextLevel level=1 scope=1 begin=1 end=76\n"
- " 1 CurrentCtx scope=0 begin=0 end=0"
+ " 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
+ " 1 ContextLevel level=1 scope=2 begin=3 end=76\n"
" 2 ContextVar level=1 begin=9 end=76 name=x\n"
" 3 StackVar scope=2 begin=11 end=76 name=b\n",
CaptureVarsAtLine(lib, "a", 10));
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index b92feae..f25d71a 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -139,44 +139,44 @@
void LocalScope::AllocateContextVariable(LocalVariable* variable,
LocalScope** context_owner) {
ASSERT(variable->is_captured());
- ASSERT(variable->owner()->loop_level() == loop_level());
- if (num_context_variables_ == 0) {
- // This scope will allocate and chain a new context.
- int new_context_level = ((*context_owner) == NULL) ?
- 1 : (*context_owner)->context_level() + 1;
- // This scope becomes the current context owner.
- *context_owner = this;
- set_context_level(new_context_level);
- }
+ ASSERT(variable->owner() == this);
// The context level in the owner scope of a captured variable indicates at
// code generation time how far to walk up the context chain in order to
// access the variable from the current context level.
- if (!variable->owner()->HasContextLevel()) {
- ASSERT(variable->owner() != this);
- variable->owner()->set_context_level(context_level());
+ if ((*context_owner) == NULL) {
+ ASSERT(num_context_variables_ == 0);
+ // This scope becomes the current context owner.
+ set_context_level(1);
+ *context_owner = this;
+ } else if ((*context_owner)->loop_level() < loop_level()) {
+ // The captured variable is at a deeper loop level than the current context.
+ // This scope will allocate and chain a new context.
+ ASSERT(num_context_variables_ == 0);
+ // This scope becomes the current context owner.
+ set_context_level((*context_owner)->context_level() + 1);
+ *context_owner = this;
} else {
- ASSERT(variable->owner()->context_level() == context_level());
+ // Allocate the captured variable in the current context.
+ if (!HasContextLevel()) {
+ ASSERT(variable->owner() != *context_owner);
+ set_context_level((*context_owner)->context_level());
+ } else {
+ ASSERT(context_level() == (*context_owner)->context_level());
+ }
}
- variable->set_index(num_context_variables_++);
+ variable->set_index((*context_owner)->num_context_variables_++);
}
int LocalScope::AllocateVariables(int first_parameter_index,
int num_parameters,
int first_frame_index,
- LocalScope* loop_owner,
- LocalScope** context_owner,
+ LocalScope* context_owner,
bool* found_captured_variables) {
// We should not allocate variables of nested functions while compiling an
// enclosing function.
ASSERT(function_level() == 0);
ASSERT(num_parameters >= 0);
-
- // Keep track of the current loop owner scope, that is of the highest parent
- // scope at the same loop level as this scope.
- if (loop_level() > loop_owner->loop_level()) {
- loop_owner = this;
- }
// Parameters must be listed first and must all appear in the top scope.
ASSERT(num_parameters <= num_variables());
int pos = 0; // Current variable position.
@@ -194,7 +194,7 @@
// context, where it gets copied to. The parameter index reflects the
// context allocation index.
frame_index--;
- loop_owner->AllocateContextVariable(parameter, context_owner);
+ AllocateContextVariable(parameter, &context_owner);
*found_captured_variables = true;
} else {
parameter->set_index(frame_index--);
@@ -208,7 +208,7 @@
pos++;
if (variable->owner() == this) {
if (variable->is_captured()) {
- loop_owner->AllocateContextVariable(variable, context_owner);
+ AllocateContextVariable(variable, &context_owner);
*found_captured_variables = true;
} else {
variable->set_index(frame_index--);
@@ -216,27 +216,19 @@
}
}
// Allocate variables of all children.
- int min_frame_index = frame_index;
+ int min_frame_index = frame_index; // Frame index decreases with allocations.
LocalScope* child = this->child();
while (child != NULL) {
- LocalScope* child_context_owner = *context_owner;
int const dummy_parameter_index = 0; // Ignored, since no parameters.
int const num_parameters_in_child = 0; // No parameters in children scopes.
int child_frame_index = child->AllocateVariables(dummy_parameter_index,
num_parameters_in_child,
frame_index,
- loop_owner,
- &child_context_owner,
+ context_owner,
found_captured_variables);
if (child_frame_index < min_frame_index) {
min_frame_index = child_frame_index;
}
- // A context allocated at a deeper loop level than the current loop level is
- // not shared between children.
- if ((child_context_owner != *context_owner) &&
- (child_context_owner->loop_level() <= loop_owner->loop_level())) {
- *context_owner = child_context_owner; // Share context between siblings.
- }
child = child->sibling();
}
return min_frame_index;
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index 2cbb3f0..faa56a8 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -313,8 +313,7 @@
int AllocateVariables(int first_parameter_index,
int num_parameters,
int first_frame_index,
- LocalScope* loop_owner,
- LocalScope** context_owner,
+ LocalScope* context_owner,
bool* found_captured_variables);
// Creates variable info for the scope and all its nested scopes.
diff --git a/tests/compiler/dart2js/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await_js_transform_test.dart
index a193616..36aa10d 100644
--- a/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -597,7 +597,7 @@
return thenHelper(foo2(), __body, __completer);
case 11:
// returning from await.
- i = __result;
+ i += __result;
// goto for condition
__goto = 3;
break;
@@ -1059,4 +1059,83 @@
}
return thenHelper(null, __body, __completer, null);
}""");
+
+ testTransform("""
+ function(m) async {
+ var exception = 1;
+ try {
+ await 42;
+ throw 42;
+ } catch (exception) {
+ exception = await 10;
+ exception += await 10;
+ exception++;
+ exception--;
+ ++exception;
+ --exception;
+ exception += 10;
+ }
+ print(exception);
+ }""", """
+function(m) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __next = [], exception, __exception;
+ function __body(__errorCode, __result) {
+ if (__errorCode === 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
+ while (true)
+ switch (__goto) {
+ case 0:
+ // Function start
+ exception = 1;
+ __handler = 3;
+ __goto = 6;
+ return thenHelper(42, __body, __completer);
+ case 6:
+ // returning from await.
+ throw 42;
+ __handler = 1;
+ // goto after finally
+ __goto = 5;
+ break;
+ case 3:
+ // catch
+ __handler = 2;
+ __exception = __currentError;
+ __goto = 7;
+ return thenHelper(10, __body, __completer);
+ case 7:
+ // returning from await.
+ __exception = __result;
+ __goto = 8;
+ return thenHelper(10, __body, __completer);
+ case 8:
+ // returning from await.
+ __exception += __result;
+ __exception++;
+ __exception--;
+ ++__exception;
+ --__exception;
+ __exception += 10;
+ // goto after finally
+ __goto = 5;
+ break;
+ case 2:
+ // uncaught
+ // goto rethrow
+ __goto = 1;
+ break;
+ case 5:
+ // after finally
+ print(exception);
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ }
+ return thenHelper(null, __body, __completer, null);
+}""");
}
diff --git a/tests/language/async_await_catch_regression_test.dart b/tests/language/async_await_catch_regression_test.dart
new file mode 100644
index 0000000..b0df58e
--- /dev/null
+++ b/tests/language/async_await_catch_regression_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+foo() async {
+ throw 42;
+}
+
+test() async {
+ var exception;
+ try {
+ await foo();
+ } catch (e) {
+ print(await(e));
+ await (exception = await e);
+ }
+ Expect.equals(42, exception);
+}
+
+main() {
+ asyncStart();
+ test().then((_) => asyncEnd());
+}
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 2d179b1..567fdbd 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -58,7 +58,6 @@
vm/*: Skip # Issue 12699
[ $compiler == dart2js && $checked ]
-await_postfix_expr_test: Fail # Issue 22742
type_variable_bounds_test/02: Fail # Issue 12702
type_variable_bounds2_test/01: Fail # Issue 12702
type_variable_bounds2_test/04: Fail # Issue 12702
diff --git a/tests/language/regress_22858_test.dart b/tests/language/regress_22858_test.dart
new file mode 100644
index 0000000..a22ded5
--- /dev/null
+++ b/tests/language/regress_22858_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+main() {
+ var good = "good";
+
+ f1() {
+ {
+ var bad = "bad";
+ f2() { bad; }
+ }
+
+ Expect.equals("good", good);
+ do {
+ Expect.equals("good", good);
+ int ugly = 0;
+ f3() { ugly; }
+ } while (false);
+ }
+
+ f1();
+}
diff --git a/tools/VERSION b/tools/VERSION
index 669823c..6c07f66 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 9
PATCH 0
PRERELEASE 10
-PRERELEASE_PATCH 10
+PRERELEASE_PATCH 11