Roll Kernel to fix an async bug.
There was a bug in the translation of await in finally when there
was a return in the try block.
The new async/async* translation revealed a bug in the scoping of
labels. Labels from enclosing functions were visible in nested
functions. That bug is fixed here.
BUG=
[email protected]
Review URL: https://chromereviews.googleplex.com/536237014 .
diff --git a/DEPS b/DEPS
index 309453a..0c9ae31 100644
--- a/DEPS
+++ b/DEPS
@@ -57,7 +57,7 @@
"dart_style_tag": "@0.2.9+1",
"dartdoc_tag" : "@v0.9.7+3",
"fixnum_tag": "@0.10.5",
- "kernel_rev": "@480abf7604fd64b96bd4b974352db034179f413a",
+ "kernel_rev": "@290f955760a219902e4d5b716668bff29711d1ab",
"func_tag": "@0.1.0",
"glob_tag": "@1.1.3",
"html_tag" : "@0.13.0",
diff --git a/runtime/vm/dil_binary.cc b/runtime/vm/dil_binary.cc
index 7eaeb13..dbc88b5 100644
--- a/runtime/vm/dil_binary.cc
+++ b/runtime/vm/dil_binary.cc
@@ -390,25 +390,45 @@
T* builder_;
};
+// Unlike other scopes, labels from enclosing functions are not visible in
+// nested functions. The LabelScope class is used to hide outer labels.
+template<typename Builder, typename Block>
+class LabelScope {
+ public:
+ explicit LabelScope(Builder* builder) : builder_(builder) {
+ outer_block_ = builder_->labels();
+ builder_->set_labels(&block_);
+ }
+ ~LabelScope() {
+ builder_->set_labels(outer_block_);
+ }
+
+ private:
+ Builder* builder_;
+ Block block_;
+ Block* outer_block_;
+};
+
class ReaderHelper {
public:
- ReaderHelper() : program_(NULL) {}
- ~ReaderHelper() {}
+ ReaderHelper() : program_(NULL), labels_(NULL) {}
Program* program() { return program_; }
void set_program(Program* program) { program_ = program; }
BlockStack<VariableDeclaration>& variables() { return scope_; }
BlockStack<TypeParameter>& type_parameters() { return type_parameters_; }
- BlockStack<LabeledStatement>& lables() { return labels_; }
BlockStack<SwitchCase>& switch_cases() { return switch_cases_; }
+ BlockStack<LabeledStatement>* labels() { return labels_; }
+ void set_labels(BlockStack<LabeledStatement>* labels) { labels_ = labels; }
+
private:
Program* program_;
BlockStack<VariableDeclaration> scope_;
BlockStack<TypeParameter> type_parameters_;
- BlockStack<LabeledStatement> labels_;
BlockStack<SwitchCase> switch_cases_;
+ BlockStack<LabeledStatement>* labels_;
};
class Reader {
@@ -533,6 +553,8 @@
class WriterHelper {
public:
+ WriterHelper() : labels_(NULL) {}
+
void SetProgram(Program* program) {
program_ = program;
for (int i = 0; i < program->libraries().length(); i++) {
@@ -580,9 +602,11 @@
BlockMap<VariableDeclaration>& variables() { return scope_; }
BlockMap<TypeParameter>& type_parameters() { return type_parameters_; }
- BlockMap<LabeledStatement>& lables() { return labels_; }
BlockMap<SwitchCase>& switch_cases() { return switch_cases_; }
+ BlockMap<LabeledStatement>* labels() { return labels_; }
+ void set_labels(BlockMap<LabeledStatement>* labels) { labels_ = labels; }
+
private:
Program* program_;
@@ -595,8 +619,8 @@
BlockMap<VariableDeclaration> scope_;
BlockMap<TypeParameter> type_parameters_;
- BlockMap<LabeledStatement> labels_;
BlockMap<SwitchCase> switch_cases_;
+ BlockMap<LabeledStatement>* labels_;
};
class Writer {
@@ -2213,31 +2237,31 @@
LabeledStatement* LabeledStatement::ReadFrom(Reader* reader) {
TRACE_READ_OFFSET();
LabeledStatement* stmt = new LabeledStatement();
- reader->helper()->lables().Push(stmt);
+ reader->helper()->labels()->Push(stmt);
stmt->body_ = Statement::ReadFrom(reader);
- reader->helper()->lables().Pop(stmt);
+ reader->helper()->labels()->Pop(stmt);
return stmt;
}
void LabeledStatement::WriteTo(Writer* writer) {
TRACE_WRITE_OFFSET();
writer->WriteTag(kLabeledStatement);
- writer->helper()->lables().Push(this);
+ writer->helper()->labels()->Push(this);
body_->WriteTo(writer);
- writer->helper()->lables().Pop(this);
+ writer->helper()->labels()->Pop(this);
}
BreakStatement* BreakStatement::ReadFrom(Reader* reader) {
TRACE_READ_OFFSET();
BreakStatement* stmt = new BreakStatement();
- stmt->target_ = reader->helper()->lables().Lookup(reader->ReadUInt());
+ stmt->target_ = reader->helper()->labels()->Lookup(reader->ReadUInt());
return stmt;
}
void BreakStatement::WriteTo(Writer* writer) {
TRACE_WRITE_OFFSET();
writer->WriteTag(kBreakStatement);
- writer->WriteUInt(writer->helper()->lables().Lookup(target_));
+ writer->WriteUInt(writer->helper()->labels()->Lookup(target_));
}
WhileStatement* WhileStatement::ReadFrom(Reader* reader) {
@@ -2750,6 +2774,8 @@
function->return_type_ = DartType::ReadFrom(reader);
function->inferred_return_value_ = reader->ReadOptional<InferredValue>();
+ LabelScope<ReaderHelper, BlockStack<LabeledStatement> > labels(
+ reader->helper());
VariableScope<ReaderHelper> vars(reader->helper());
function->body_ = reader->ReadOptional<Statement>();
return function;
@@ -2767,6 +2793,8 @@
return_type_->WriteTo(writer);
writer->WriteOptional<InferredValue>(inferred_return_value_);
+ LabelScope<WriterHelper, BlockMap<LabeledStatement> > labels(
+ writer->helper());
VariableScope<WriterHelper> vars(writer->helper());
writer->WriteOptional<Statement>(body_);
}
diff --git a/tests/language/async_await_test.dart b/tests/language/async_await_test.dart
index 88fc1a5..b5f6c00 100644
--- a/tests/language/async_await_test.dart
+++ b/tests/language/async_await_test.dart
@@ -807,22 +807,20 @@
return expect42(f());
});
- // Fails (x is 0, not 37) due to incorrect placement of inlined finally code
- // (not in the future).
- // test("await in finally", () {
- // var x = 0;
- // f() async {
- // try {
- // return id(42);
- // } finally {
- // x = await new Future.value(37);
- // }
- // }
- // return f().then((v) {
- // expect(v, equals(42));
- // expect(x, equals(37));
- // });
- // });
+ test("await in finally", () {
+ var x = 0;
+ f() async {
+ try {
+ return id(42);
+ } finally {
+ x = await new Future.value(37);
+ }
+ }
+ return f().then((v) {
+ expect(v, equals(42));
+ expect(x, equals(37));
+ });
+ });
test("await err in body", () {
f() async {
@@ -872,34 +870,34 @@
return expect42(f());
});
- // test("await in body, override in finally", () {
- // f() async {
- // label: try {
- // return await new Future.value(37);
- // } finally {
- // break label;
- // }
- // return id(42);
- // }
- // return expect42(f());
- // });
+ test("await in body, override in finally", () {
+ f() async {
+ label: try {
+ return await new Future.value(37);
+ } finally {
+ break label;
+ }
+ return id(42);
+ }
+ return expect42(f());
+ });
- // test("await, override in finally", () {
- // var x = 0;
- // f() async {
- // label: try {
- // return 87;
- // } finally {
- // x = await new Future.value(37);
- // break label;
- // }
- // return id(42);
- // }
- // return f().then((v) {
- // expect(v, equals(42));
- // expect(x, equals(37));
- // });
- // });
+ test("await, override in finally", () {
+ var x = 0;
+ f() async {
+ label: try {
+ return 87;
+ } finally {
+ x = await new Future.value(37);
+ break label;
+ }
+ return id(42);
+ }
+ return f().then((v) {
+ expect(v, equals(42));
+ expect(x, equals(37));
+ });
+ });
test("throw in body, await, override in finally 3", () {
var x = 0;
@@ -930,19 +928,19 @@
return expect42(f());
});
- // test("await in body, no-exit in finally", () {
- // f() async {
- // for (int i = 0; i < 10; i++) {
- // try {
- // return await i;
- // } finally {
- // continue;
- // }
- // }
- // return id(42);
- // }
- // return expect42(f());
- // });
+ test("await in body, no-exit in finally", () {
+ f() async {
+ for (int i = 0; i < 10; i++) {
+ try {
+ return await i;
+ } finally {
+ continue;
+ }
+ }
+ return id(42);
+ }
+ return expect42(f());
+ });
test("no-exit after await in finally", () {
f() async {
@@ -980,54 +978,54 @@
});
});
- // test("no-exit before await in finally 2", () {
- // f() async {
- // for (int i = 0; i < 10; i++) {
- // try {
- // return i;
- // } finally {
- // if (i >= 0) continue;
- // await new Future.value(42);
- // }
- // }
- // return id(42);
- // }
- // return expect42(f());
- // });
+ test("no-exit before await in finally 2", () {
+ f() async {
+ for (int i = 0; i < 10; i++) {
+ try {
+ return i;
+ } finally {
+ if (i >= 0) continue;
+ await new Future.value(42);
+ }
+ }
+ return id(42);
+ }
+ return expect42(f());
+ });
- // test("no-exit after await in finally", () {
- // f() async {
- // for (int i = 0; i < 10; i++) {
- // try {
- // return i;
- // } finally {
- // await new Future.value(42);
- // continue;
- // }
- // }
- // return id(42);
- // }
- // return expect42(f());
- // });
+ test("no-exit after await in finally", () {
+ f() async {
+ for (int i = 0; i < 10; i++) {
+ try {
+ return i;
+ } finally {
+ await new Future.value(42);
+ continue;
+ }
+ }
+ return id(42);
+ }
+ return expect42(f());
+ });
- // test("nested finallies", () {
- // var x = 0;
- // f() async {
- // try {
- // try {
- // return 42;
- // } finally {
- // x = await new Future.value(37);
- // }
- // } finally {
- // x += await new Future.value(37);
- // }
- // }
- // return f().then((v) {
- // expect(v, equals(42));
- // expect(x, equals(74));
- // });
- // });
+ test("nested finallies", () {
+ var x = 0;
+ f() async {
+ try {
+ try {
+ return 42;
+ } finally {
+ x = await new Future.value(37);
+ }
+ } finally {
+ x += await new Future.value(37);
+ }
+ }
+ return f().then((v) {
+ expect(v, equals(42));
+ expect(x, equals(74));
+ });
+ });
test("nested finallies 2", () {
var x = 0;
@@ -1049,23 +1047,25 @@
});
});
- // test("nested finallies 3", () {
- // var x = 0;
- // f() async {
- // label: try {
- // try {
- // break label;
- // } finally {
- // return await new Future.value(42);
- // }
- // } finally {
- // break label;
- // }
- // return 42;
- // }
- // return expect42(f());
- // });
+ test("nested finallies 3", () {
+ var x = 0;
+ f() async {
+ label: try {
+ try {
+ break label;
+ } finally {
+ return await new Future.value(42);
+ }
+ } finally {
+ break label;
+ }
+ return 42;
+ }
+ return expect42(f());
+ });
+ // Expected: 'err'
+ // Actual: NullThrownError
// test("nested finallies, throw", () {
// var x = 0;
// f() async {
@@ -1127,23 +1127,23 @@
return expect42(f());
});
- // test("await in finally", () {
- // var x = 0;
- // f() async {
- // try {
- // return id(42);
- // } catch (e) {
- // throw null;
- // } finally {
- // x = await new Future.value(37);
- // if (id(42) == id(10)) return 10;
- // }
- // }
- // return f().then((v) {
- // expect(v, equals(42));
- // expect(x, equals(37));
- // });
- // });
+ test("await in finally", () {
+ var x = 0;
+ f() async {
+ try {
+ return id(42);
+ } catch (e) {
+ throw null;
+ } finally {
+ x = await new Future.value(37);
+ if (id(42) == id(10)) return 10;
+ }
+ }
+ return f().then((v) {
+ expect(v, equals(42));
+ expect(x, equals(37));
+ });
+ });
});
group("switch", () {
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index db67f27..3d1d017 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -22,8 +22,6 @@
accessor_conflict_import_prefixed_test: RuntimeError
accessor_conflict_import_test: RuntimeError
assertion_test: RuntimeError
-async_break_in_finally_test: RuntimeError
-async_control_structures_test: RuntimeError
async_star_cancel_and_throw_in_finally_test: RuntimeError
async_star_cancel_while_paused_test: RuntimeError
async_star_regression_fisk_test: Timeout
@@ -35,8 +33,6 @@
asyncstar_throw_in_catch_test: Timeout
asyncstar_yield_test: Timeout
asyncstar_yieldstar_test: Timeout
-await_exceptions_test: RuntimeError
-await_future_test: RuntimeError
bad_constructor_test/05: CompileTimeError
bad_raw_string_negative_test: Fail
cha_deopt1_test: RuntimeError
@@ -353,8 +349,6 @@
accessor_conflict_import_prefixed_test: RuntimeError
accessor_conflict_import_test: RuntimeError
assertion_test: RuntimeError
-async_break_in_finally_test: RuntimeError
-async_control_structures_test: RuntimeError
async_star_cancel_and_throw_in_finally_test: RuntimeError
async_star_cancel_while_paused_test: RuntimeError
async_star_regression_fisk_test: Timeout
@@ -366,8 +360,6 @@
asyncstar_throw_in_catch_test: Timeout
asyncstar_yield_test: Timeout
asyncstar_yieldstar_test: Timeout
-await_exceptions_test: RuntimeError
-await_future_test: RuntimeError
bad_constructor_test/05: CompileTimeError
bad_raw_string_negative_test: Fail
cha_deopt1_test: RuntimeError