mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 15:11:35 +00:00
af4da780be
The new implementation is based on suspend/resume stubs and doesn't use desugaring of async functions on kernel AST. Previously, new implementation of async/async* was only supported in AOT mode. This change adds all necessary bits for the JIT mode: * Suspending variable-length frames (for unoptimized code). * Handling of Code and pool pointers in Dart stack frames. * OSR. * Deoptimization. * Hot reload. * Debugger. The new implementation is not enabled in JIT mode yet. Design doc: go/compact-async-await. TEST=ci Issue: https://github.com/dart-lang/sdk/issues/48378 Change-Id: I477d6684bdce7cbc1edb179ae2271ff598b7dcc5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246081 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
2308 lines
47 KiB
Dart
2308 lines
47 KiB
Dart
// 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.
|
|
|
|
// @dart = 2.9
|
|
|
|
// VMOptions=
|
|
// VMOptions=--optimization-counter-threshold=5
|
|
|
|
import "package:expect/expect.dart";
|
|
import "package:async_helper/async_helper.dart";
|
|
import "dart:async";
|
|
|
|
typedef dynamic DynamicToDynamic(dynamic d);
|
|
|
|
main() {
|
|
asyncStart();
|
|
group("basic", () {
|
|
test("async w/o await", () {
|
|
f() async {
|
|
return id(42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("async starts synchronously", () {
|
|
// Calling an "async" function starts immediately.
|
|
var result = [];
|
|
f() async {
|
|
result.add(1);
|
|
return id(42);
|
|
}
|
|
|
|
;
|
|
var future = f();
|
|
result.add(0);
|
|
return future.whenComplete(() {
|
|
expect(result, equals([1, 0]));
|
|
});
|
|
});
|
|
|
|
test("async throws", () {
|
|
f() async {
|
|
throw "err";
|
|
return id(42);
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await future", () {
|
|
f() async {
|
|
var v = await new Future.value(42);
|
|
return v;
|
|
}
|
|
|
|
;
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await value", () {
|
|
f() async {
|
|
var v = await id(42);
|
|
return v;
|
|
}
|
|
|
|
;
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await null", () {
|
|
f() async {
|
|
var v = await null;
|
|
expect(v, equals(null));
|
|
}
|
|
|
|
;
|
|
return f();
|
|
});
|
|
|
|
test("await await", () {
|
|
f() async {
|
|
return await await new Future.value(42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await fake value future", () {
|
|
f() async {
|
|
return await new FakeValueFuture(42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await fake error future", () {
|
|
f() async {
|
|
return await new FakeErrorFuture("err");
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await value is delayed", () {
|
|
f() async {
|
|
bool x = false;
|
|
scheduleMicrotask(() {
|
|
x = true;
|
|
});
|
|
var y = await true;
|
|
expect(x, equals(y));
|
|
}
|
|
|
|
return f();
|
|
});
|
|
|
|
test("await throw", () {
|
|
f() async {
|
|
await (throw "err"); // Check grammar: Are parentheses necessary?
|
|
return id(42);
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("throw before await", () {
|
|
f() async {
|
|
var x = throw "err";
|
|
await x; // Check grammar: Are parentheses necessary?
|
|
return id(42);
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
if (assertStatementsEnabled) {
|
|
test("assert before await", () {
|
|
f(v) async {
|
|
assert(v == 87);
|
|
return await new Future.microtask(() => 42);
|
|
}
|
|
|
|
return f(42).then((_) {
|
|
fail("assert didn't throw");
|
|
}, onError: (e, s) {
|
|
expect(e is AssertionError, isTrue);
|
|
});
|
|
});
|
|
|
|
test("assert after await", () {
|
|
f(v) async {
|
|
var x = await new Future.microtask(() => 42);
|
|
assert(v == 87);
|
|
return x;
|
|
}
|
|
|
|
return f(42).then((_) {
|
|
fail("assert didn't throw");
|
|
}, onError: (e, s) {
|
|
expect(e is AssertionError, isTrue);
|
|
});
|
|
});
|
|
}
|
|
|
|
test("async await error", () {
|
|
f() async {
|
|
await new Future.error("err");
|
|
return id(42);
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("async flattens futures", () {
|
|
f() async {
|
|
return new Future.value(42); // Not awaited.
|
|
}
|
|
|
|
;
|
|
return f().then((v) {
|
|
expect(v, equals(42)); // And not a Future with value 42.
|
|
});
|
|
});
|
|
|
|
test("async flattens futures, error", () {
|
|
f() async {
|
|
return new Future.error("err"); // Not awaited.
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await for", () {
|
|
f(Stream<int> s) async {
|
|
int i = 0;
|
|
await for (int v in s) {
|
|
i += v;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
return f(mkStream()).then((v) {
|
|
expect(v, equals(45)); // 0 + 1 + ... + 9
|
|
});
|
|
});
|
|
|
|
test("await for w/ await", () {
|
|
f(Stream<int> s) async {
|
|
int i = 0;
|
|
await for (int v in s) {
|
|
i += await new Future.value(v);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
return f(mkStream()).then((v) {
|
|
expect(v, equals(45)); // 0 + 1 + ... + 9
|
|
});
|
|
});
|
|
|
|
test("await for empty", () {
|
|
f(Stream<int> s) async {
|
|
int v = 0;
|
|
await for (int i in s) {
|
|
v += i;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
var s = (new StreamController<int>()..close()).stream;
|
|
return f(s).then((v) {
|
|
expect(v, equals(0));
|
|
});
|
|
});
|
|
|
|
if (assertStatementsEnabled) {
|
|
test("await for w/ await, asseert", () {
|
|
f(Stream<int> s) async {
|
|
int i = 0;
|
|
await for (int v in s) {
|
|
i += await new Future.microtask(() => v);
|
|
assert(v < 8);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
return f(mkStream()).then((v) {
|
|
fail("assert didn't throw");
|
|
}, onError: (e, s) {
|
|
expect(e is AssertionError, isTrue);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
group("for", () {
|
|
test("await in for-loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
v += await new Future.value(42);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * id(42)));
|
|
});
|
|
});
|
|
|
|
test("await in for-init", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = await new Future.value(42); i >= 0; i -= 10) {
|
|
v += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * 5));
|
|
});
|
|
});
|
|
|
|
test("await in for-test", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < await new Future.value(42); i += 10) {
|
|
v += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * 5));
|
|
});
|
|
});
|
|
|
|
test("await in for-incr", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 100; i += await new Future.value(42)) {
|
|
v += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * 3));
|
|
});
|
|
});
|
|
|
|
test("await err in for-loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
v += await new Future.error("err");
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await err in for-init", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = await new Future.error("err"); i >= 0; i -= 10) {
|
|
v += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await err in for-test", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < await new Future.error("err"); i += 10) {
|
|
v += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await err in for-incr", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 100; i += await new Future.error("err")) {
|
|
v += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await in empty for-loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i > 0; i += 1) {
|
|
v += await new Future.value(42);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(0));
|
|
});
|
|
});
|
|
|
|
test("await in empty for-loop 2", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i > 0; i += await new Future.value(1)) {
|
|
v += 1;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(0));
|
|
});
|
|
});
|
|
|
|
test("break before await in for-loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 10; i += 1) {
|
|
if (i == 2) break;
|
|
v += await new Future.value(42);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 2));
|
|
});
|
|
});
|
|
|
|
test("break before await in for-loop 2", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 10; i += await new Future.value(1)) {
|
|
if (i == 2) break;
|
|
v += id(42);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 2));
|
|
});
|
|
});
|
|
|
|
test("continue before await", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 10; i += 1) {
|
|
if (i == 2) continue;
|
|
v += await new Future.value(42);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 9));
|
|
});
|
|
});
|
|
|
|
test("continue after await", () {
|
|
f() async {
|
|
int v = 0;
|
|
for (int i = 0; i < 10; i += 1) {
|
|
var j = await new Future.value(42);
|
|
if (i == 2) continue;
|
|
v += j;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 9));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("while", () {
|
|
test("await in while-loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < 10) {
|
|
v += await new Future.value(42);
|
|
i++;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * id(42)));
|
|
});
|
|
});
|
|
|
|
test("await in while-test", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < await new Future.value(42)) {
|
|
v += 10;
|
|
i += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * 5));
|
|
});
|
|
});
|
|
|
|
test("await err in loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < 10) {
|
|
v += await new Future.error("err");
|
|
i++;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("await err in test", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < await new Future.error("err")) {
|
|
v += 10;
|
|
i += 10;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return throwsErr(f());
|
|
});
|
|
|
|
test("break before await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < 10) {
|
|
if (i == 2) break;
|
|
v += await new Future.value(42);
|
|
i += 1;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 2));
|
|
});
|
|
});
|
|
|
|
test("break after await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < 10) {
|
|
v += await new Future.value(42);
|
|
if (i == 2) break;
|
|
i += 1;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 3));
|
|
});
|
|
});
|
|
|
|
test("continue before await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < 10) {
|
|
i += 1;
|
|
if (i == 2) continue;
|
|
v += await new Future.value(42);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 9));
|
|
});
|
|
});
|
|
|
|
test("continue after await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
while (i < 10) {
|
|
i += 1;
|
|
int j = await new Future.value(42);
|
|
if (i == 2) continue;
|
|
v += j;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 9));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("do-while", () {
|
|
test("await in loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
v += await new Future.value(42);
|
|
i++;
|
|
} while (i < 10);
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * id(42)));
|
|
});
|
|
});
|
|
|
|
test("await in test", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
v += 10;
|
|
i += 10;
|
|
} while (i < await new Future.value(42));
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10 * 5));
|
|
});
|
|
});
|
|
|
|
test("await err in loop", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
v += await new Future.error("err");
|
|
i++;
|
|
} while (i < 10);
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("await err in test", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
v += 10;
|
|
i += 10;
|
|
} while (i < await new Future.error("err"));
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("break before await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
if (i == 2) break;
|
|
v += await new Future.value(42);
|
|
i += 1;
|
|
} while (i < 10);
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 2));
|
|
});
|
|
});
|
|
|
|
test("break after await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
v += await new Future.value(42);
|
|
if (i == 2) break;
|
|
i += 1;
|
|
} while (i < 10);
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 3));
|
|
});
|
|
});
|
|
|
|
test("continue before await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
i += 1;
|
|
if (i == 2) continue;
|
|
v += await new Future.value(42);
|
|
} while (i < 10);
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 9));
|
|
});
|
|
});
|
|
|
|
test("continue after await", () {
|
|
f() async {
|
|
int v = 0;
|
|
int i = 0;
|
|
do {
|
|
i += 1;
|
|
int j = await new Future.value(42);
|
|
if (i == 2) continue;
|
|
v += j;
|
|
} while (i < 10);
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42 * 9));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("for-in", () {
|
|
test("await in for-in", () {
|
|
f() async {
|
|
var v = 0;
|
|
for (var fut in [1, 2, 3].map((v) => new Future.value(v))) {
|
|
v += await fut;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(6));
|
|
});
|
|
});
|
|
|
|
test("await in for-in iterable", () {
|
|
f() async {
|
|
var v = 0;
|
|
for (var i in await new Future.value([1, 2, 3])) {
|
|
v += i;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(6));
|
|
});
|
|
});
|
|
|
|
test("await err in for-in", () {
|
|
f() async {
|
|
var v = 0;
|
|
for (var fut in [1, 2, 3].map(
|
|
(v) => (v != 1) ? new Future.value(v) : new Future.error("err"))) {
|
|
v += await fut;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("await err in for-in iterable", () {
|
|
f() async {
|
|
var v = 0;
|
|
for (var i in await new Future.error("err")) {
|
|
v += i;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("break before await in for-in", () {
|
|
f() async {
|
|
var v = 0;
|
|
for (var fut in [1, 2, 3].map((v) => new Future.value(v))) {
|
|
if (v == 3) break;
|
|
v += await fut;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(3));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("try-catch", () {
|
|
test("try-no-catch", () {
|
|
f() async {
|
|
try {
|
|
return await id(42);
|
|
} catch (e) {
|
|
return 37;
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await in body", () {
|
|
f() async {
|
|
try {
|
|
await new Future.error(42);
|
|
} catch (e) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("throw before await in body", () {
|
|
int i = id(0);
|
|
f() async {
|
|
try {
|
|
if (i >= 0) throw id(42);
|
|
return await new Future.value(10);
|
|
} catch (e) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("try-catch await in catch", () {
|
|
f() async {
|
|
try {
|
|
throw id(42);
|
|
} catch (e) {
|
|
return await new Future.value(e);
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("try-catch await error in catch", () {
|
|
f() async {
|
|
try {
|
|
throw id(42);
|
|
} catch (e) {
|
|
await new Future.error("err");
|
|
}
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("try-catch-rethrow", () {
|
|
f() async {
|
|
try {
|
|
await new Future.error("err");
|
|
} catch (e) {
|
|
if (e == id(42)) return;
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("try-finally", () {
|
|
test("await in body", () {
|
|
f() async {
|
|
try {
|
|
return await new Future.value(42);
|
|
} finally {
|
|
// Don't do anything.
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
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 {
|
|
try {
|
|
return await new Future.error("err");
|
|
} finally {
|
|
// Don't do anything.
|
|
}
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("await err in finally", () {
|
|
f() async {
|
|
try {
|
|
return id(42);
|
|
} finally {
|
|
await new Future.error("err");
|
|
}
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("await err in both", () {
|
|
f() async {
|
|
try {
|
|
await new Future.error("not err");
|
|
} finally {
|
|
await new Future.error("err");
|
|
}
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
});
|
|
|
|
test("await err in body, override in finally", () {
|
|
f() async {
|
|
try {
|
|
return await new Future.error("err");
|
|
} finally {
|
|
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("throw in body, await, override in finally 3", () {
|
|
var x = 0;
|
|
f() async {
|
|
label:
|
|
try {
|
|
throw "err";
|
|
} 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 err in body, override in finally 2", () {
|
|
f() async {
|
|
label:
|
|
try {
|
|
return await new Future.error("err");
|
|
} finally {
|
|
break label;
|
|
}
|
|
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 {
|
|
int i = 0;
|
|
for (; i < 10; i++) {
|
|
try {
|
|
break;
|
|
} finally {
|
|
await new Future.value(42);
|
|
continue;
|
|
}
|
|
}
|
|
return id(i);
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(10));
|
|
});
|
|
});
|
|
|
|
test("exit after continue, await in finally", () {
|
|
f() async {
|
|
int i = 0;
|
|
for (; i < 10; i++) {
|
|
try {
|
|
continue;
|
|
} finally {
|
|
await new Future.value(42);
|
|
break;
|
|
}
|
|
}
|
|
return id(i);
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(0));
|
|
});
|
|
});
|
|
|
|
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("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;
|
|
f() async {
|
|
label:
|
|
try {
|
|
try {
|
|
break label;
|
|
} finally {
|
|
x = await new Future.value(37);
|
|
}
|
|
} finally {
|
|
x += await new Future.value(37);
|
|
}
|
|
return 42;
|
|
}
|
|
|
|
return f().then((v) {
|
|
expect(v, equals(42));
|
|
expect(x, equals(74));
|
|
});
|
|
});
|
|
|
|
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, throw", () {
|
|
var x = 0;
|
|
f() async {
|
|
try {
|
|
try {
|
|
throw "err";
|
|
} finally {
|
|
x = await new Future.value(37);
|
|
}
|
|
} finally {
|
|
x += await new Future.value(37);
|
|
}
|
|
}
|
|
|
|
return f().then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
expect(x, equals(2 * 37));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("try-catch-finally", () {
|
|
test("await in body", () {
|
|
f() async {
|
|
try {
|
|
return await new Future.value(42);
|
|
} catch (e) {
|
|
throw null;
|
|
} finally {
|
|
if (id(42) == id(10)) return 10;
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await in catch, not hit", () {
|
|
f() async {
|
|
try {
|
|
return id(42);
|
|
} catch (e) {
|
|
await new Future.error("err");
|
|
} finally {
|
|
if (id(42) == id(10)) return 10;
|
|
}
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("await in catch, hit", () {
|
|
f() async {
|
|
try {
|
|
return throw id(42);
|
|
} catch (e) {
|
|
return await new Future.value(e);
|
|
} finally {
|
|
if (id(42) == id(10)) return 10;
|
|
}
|
|
}
|
|
|
|
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));
|
|
});
|
|
});
|
|
});
|
|
|
|
group("switch", () {
|
|
test("await in expression", () {
|
|
f(v) async {
|
|
switch (await new Future.value(v)) {
|
|
case 1:
|
|
return 1;
|
|
case 2:
|
|
return 42;
|
|
default:
|
|
return 3;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
return expect42(f(2));
|
|
});
|
|
|
|
test("await err in expression", () {
|
|
f(v) async {
|
|
switch (await new Future.error("err")) {
|
|
case 1:
|
|
return 1;
|
|
case 2:
|
|
return 42;
|
|
default:
|
|
return 3;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
return throwsErr(f(2));
|
|
});
|
|
|
|
test("await in case", () {
|
|
f(v) async {
|
|
switch (v) {
|
|
case 1:
|
|
return 1;
|
|
case 2:
|
|
return await new Future.value(42);
|
|
default:
|
|
return 3;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
return expect42(f(2));
|
|
});
|
|
|
|
test("await err in case", () {
|
|
f(v) async {
|
|
switch (v) {
|
|
case 1:
|
|
return 1;
|
|
case 2:
|
|
return await new Future.error("err");
|
|
default:
|
|
return 3;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
return throwsErr(f(2));
|
|
});
|
|
// TODO(jmesserly): restore this when we fix
|
|
// https://github.com/dart-lang/dev_compiler/issues/263
|
|
/*test("continue before await in case", () {
|
|
f(v) async {
|
|
switch (v) {
|
|
label:
|
|
case 1: return 42;
|
|
case 2:
|
|
if (v <= 2) continue label;
|
|
return await new Future.value(10);
|
|
default: return 3;
|
|
}
|
|
return null;
|
|
}
|
|
return expect42(f(2));
|
|
});
|
|
|
|
test("continue after await in case", () {
|
|
f(v) async {
|
|
switch (v) {
|
|
label:
|
|
case 1: return 42;
|
|
case 2:
|
|
await new Future.value(10);
|
|
continue label;
|
|
default: return 3;
|
|
}
|
|
return null;
|
|
}
|
|
return expect42(f(2));
|
|
});*/
|
|
});
|
|
|
|
group("if", () {
|
|
test("await in test", () {
|
|
f(v) async {
|
|
if (await new Future.value(v)) {
|
|
return 42;
|
|
} else {
|
|
return 37;
|
|
}
|
|
}
|
|
|
|
return expect42(f(true));
|
|
});
|
|
|
|
test("await err in test", () {
|
|
f(v) async {
|
|
if (await new Future.error("err")) {
|
|
return 42;
|
|
} else {
|
|
return 37;
|
|
}
|
|
}
|
|
|
|
return throwsErr(f(true));
|
|
});
|
|
|
|
test("await in then", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return await new Future.value(42);
|
|
}
|
|
return 37;
|
|
}
|
|
|
|
return expect42(f(true));
|
|
});
|
|
|
|
test("await err in then", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return await new Future.error("err");
|
|
}
|
|
return 37;
|
|
}
|
|
|
|
return throwsErr(f(true));
|
|
});
|
|
|
|
test("await in then with else", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return await new Future.value(42);
|
|
} else {
|
|
return 87;
|
|
}
|
|
return 37;
|
|
}
|
|
|
|
return expect42(f(true));
|
|
});
|
|
|
|
test("await err in then with else", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return await new Future.error("err");
|
|
} else {
|
|
return 87;
|
|
}
|
|
return 37;
|
|
}
|
|
|
|
return throwsErr(f(true));
|
|
});
|
|
|
|
test("await in else", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return 37;
|
|
} else {
|
|
return await new Future.value(42);
|
|
}
|
|
return 87;
|
|
}
|
|
|
|
return expect42(f(false));
|
|
});
|
|
|
|
test("await err in else", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return 37;
|
|
} else {
|
|
return await new Future.error("err");
|
|
}
|
|
return 87;
|
|
}
|
|
|
|
return throwsErr(f(false));
|
|
});
|
|
|
|
test("await in else-if test", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return 37;
|
|
} else if (!await new Future.value(v)) {
|
|
return 42;
|
|
} else {
|
|
return 37;
|
|
}
|
|
return 87;
|
|
}
|
|
|
|
return expect42(f(false));
|
|
});
|
|
|
|
test("await in else-if then", () {
|
|
f(v) async {
|
|
if (v) {
|
|
return 37;
|
|
} else if (!v) {
|
|
return await new Future.value(42);
|
|
} else {
|
|
return 37;
|
|
}
|
|
return 87;
|
|
}
|
|
|
|
return expect42(f(false));
|
|
});
|
|
});
|
|
|
|
group("conditional operator", () {
|
|
test("await in test", () {
|
|
f(v) async {
|
|
return (await new Future.value(v)) ? 42 : 37;
|
|
}
|
|
|
|
return expect42(f(true));
|
|
});
|
|
|
|
test("await err in test", () {
|
|
f(v) async {
|
|
return (await new Future.error("err")) ? 42 : 37;
|
|
}
|
|
|
|
return throwsErr(f(true));
|
|
});
|
|
|
|
test("await in then", () {
|
|
f(v) async {
|
|
return v ? (await new Future.value(42)) : 37;
|
|
}
|
|
|
|
return expect42(f(true));
|
|
});
|
|
|
|
test("await err in then", () {
|
|
f(v) async {
|
|
return v ? (await new Future.error("err")) : 37;
|
|
}
|
|
|
|
return throwsErr(f(true));
|
|
});
|
|
|
|
test("await in else", () {
|
|
f(v) async {
|
|
return v ? 37 : (await new Future.value(42));
|
|
}
|
|
|
|
return expect42(f(false));
|
|
});
|
|
|
|
test("await err in else", () {
|
|
f(v) async {
|
|
return v ? 37 : (await new Future.error("err"));
|
|
}
|
|
|
|
return throwsErr(f(false));
|
|
});
|
|
});
|
|
|
|
group("async declarations", () {
|
|
var f42 = new Future.value(42);
|
|
|
|
// Top-level declarations or local declarations in top-level functions.
|
|
test("topMethod", () {
|
|
return expect42(topMethod(f42));
|
|
});
|
|
|
|
test("topArrowMethod", () {
|
|
return expect42(topArrowMethod(f42));
|
|
});
|
|
|
|
test("topGetter", () {
|
|
return expect42(topGetter);
|
|
});
|
|
|
|
test("topArrowGetter", () {
|
|
return expect42(topArrowGetter);
|
|
});
|
|
|
|
test("topLocal", () {
|
|
return expect42(topLocal(f42));
|
|
});
|
|
|
|
test("topArrowLocal", () {
|
|
return expect42(topArrowLocal(f42));
|
|
});
|
|
|
|
test("topExpression", () {
|
|
return expect42(topExpression(f42));
|
|
});
|
|
|
|
test("topArrowExpression", () {
|
|
return expect42(topArrowExpression(f42));
|
|
});
|
|
|
|
test("topVarExpression", () {
|
|
return expect42(topVarExpression(f42));
|
|
});
|
|
|
|
test("topVarArrowExpression", () {
|
|
return expect42(topVarArrowExpression(f42));
|
|
});
|
|
|
|
// Static declarations or local declarations in static functions.
|
|
test("staticMethod", () {
|
|
return expect42(Async.staticMethod(f42));
|
|
});
|
|
|
|
test("staticArrowMethod", () {
|
|
return expect42(Async.staticArrowMethod(f42));
|
|
});
|
|
|
|
test("staticGetter", () {
|
|
return expect42(Async.staticGetter);
|
|
});
|
|
|
|
test("staticArrowGetter", () {
|
|
return expect42(Async.staticArrowGetter);
|
|
});
|
|
|
|
test("staticLocal", () {
|
|
return expect42(Async.staticLocal(f42));
|
|
});
|
|
|
|
test("staticArrowLocal", () {
|
|
return expect42(Async.staticArrowLocal(f42));
|
|
});
|
|
|
|
test("staticExpression", () {
|
|
return expect42(Async.staticExpression(f42));
|
|
});
|
|
|
|
test("staticArrowExpression", () {
|
|
return expect42(Async.staticArrowExpression(f42));
|
|
});
|
|
|
|
test("staticVarExpression", () {
|
|
return expect42(Async.staticVarExpression(f42));
|
|
});
|
|
|
|
test("staticVarArrowExpression", () {
|
|
return expect42(Async.staticVarArrowExpression(f42));
|
|
});
|
|
|
|
// Instance declarations or local declarations in instance functions.
|
|
var async = new Async();
|
|
|
|
test("instanceMethod", () {
|
|
return expect42(async.instanceMethod(f42));
|
|
});
|
|
|
|
test("instanceArrowMethod", () {
|
|
return expect42(async.instanceArrowMethod(f42));
|
|
});
|
|
|
|
test("instanceGetter", () {
|
|
return expect42(async.instanceGetter);
|
|
});
|
|
|
|
test("instanceArrowGetter", () {
|
|
return expect42(async.instanceArrowGetter);
|
|
});
|
|
|
|
test("instanceLocal", () {
|
|
return expect42(async.instanceLocal(f42));
|
|
});
|
|
|
|
test("instanceArrowLocal", () {
|
|
return expect42(async.instanceArrowLocal(f42));
|
|
});
|
|
|
|
test("instanceExpression", () {
|
|
return expect42(async.instanceExpression(f42));
|
|
});
|
|
|
|
test("instanceArrowExpression", () {
|
|
return expect42(async.instanceArrowExpression(f42));
|
|
});
|
|
|
|
test("instanceVarExpression", () {
|
|
return expect42(async.instanceVarExpression(f42));
|
|
});
|
|
|
|
test("instanceVarArrowExpression", () {
|
|
return expect42(async.instanceVarArrowExpression(f42));
|
|
});
|
|
|
|
// Local functions in constructor initializer list.
|
|
test("initializerExpression", () {
|
|
var async = new Async.initializer(f42);
|
|
return expect42(async.initValue);
|
|
});
|
|
|
|
test("initializerArrowExpression", () {
|
|
var async = new Async.initializerArrow(f42);
|
|
return expect42(async.initValue);
|
|
});
|
|
|
|
test("async in async", () {
|
|
return expect42(asyncInAsync(f42));
|
|
});
|
|
|
|
test("sync in async", () {
|
|
return expect42(syncInAsync(f42));
|
|
});
|
|
|
|
test("async in sync", () {
|
|
return expect42(asyncInSync(f42));
|
|
});
|
|
|
|
test("Identical and equals", () {
|
|
expect(async.instanceMethod, equals(async.instanceMethod));
|
|
expect(Async.staticMethod, same(Async.staticMethod));
|
|
expect(topMethod, same(topMethod));
|
|
});
|
|
});
|
|
|
|
group("await expression", () {
|
|
const c42 = 42;
|
|
final v42 = 42;
|
|
|
|
test("local variable", () {
|
|
var l42 = 42;
|
|
f() async {
|
|
return await l42;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("parameter", () {
|
|
f(p) async {
|
|
return await p;
|
|
}
|
|
|
|
return expect42(f(42));
|
|
});
|
|
|
|
test("final local variable", () {
|
|
f() async {
|
|
return await v42;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("const local variable", () {
|
|
f() async {
|
|
return await c42;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("unary prefix operator", () {
|
|
f() async {
|
|
return -await -42;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("suffix operator", () {
|
|
f() async {
|
|
var v = [42];
|
|
return await v[0];
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("unary postfix operator", () {
|
|
f() async {
|
|
var x = 42;
|
|
return await x++;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("suffix operator + increment", () {
|
|
f() async {
|
|
var v = [42];
|
|
return await v[0]++;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("suffix operator + increment 2", () {
|
|
f() async {
|
|
var v = [42];
|
|
return await v[await 0]++;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("unary pre-increment operator", () {
|
|
f() async {
|
|
var x = 41;
|
|
return await ++x;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("suffix operator + pre-increment", () {
|
|
f() async {
|
|
var v = [41];
|
|
return await ++v[0];
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("assignment operator", () {
|
|
f() async {
|
|
var x = 37;
|
|
return await (x = 42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("assignment-op operator", () {
|
|
f() async {
|
|
var x = 37;
|
|
return await (x += 5);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("binary operator", () {
|
|
f() async {
|
|
return await (10 + 11) + await (10 + 11);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("ternary operator", () {
|
|
f(v) async {
|
|
return await ((v == 10) ? new Future.value(42) : 37);
|
|
}
|
|
|
|
return expect42(f(10));
|
|
});
|
|
|
|
test("top-level function call", () {
|
|
f() async {
|
|
return await topMethod(42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("static function call", () {
|
|
f() async {
|
|
return await Async.staticMethod(42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("instance function call", () {
|
|
f() async {
|
|
var a = new Async();
|
|
return await a.instanceMethod(42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("top-level function call w/ await", () {
|
|
f() async {
|
|
return await topMethod(await 42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("static function call w/ await", () {
|
|
f() async {
|
|
return await Async.staticMethod(await 42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("instance function call w/ await", () {
|
|
f() async {
|
|
var a = new Async();
|
|
return await a.instanceMethod(await 42);
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("top-level getter call", () {
|
|
f() async {
|
|
return await topGetter;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("static getter call", () {
|
|
f() async {
|
|
return await Async.staticGetter;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
test("top-level getter call", () {
|
|
f() async {
|
|
var a = new Async();
|
|
return await a.instanceGetter;
|
|
}
|
|
|
|
return expect42(f());
|
|
});
|
|
|
|
if (!assertStatementsEnabled) return;
|
|
|
|
test("inside assert, true", () { // //# 03: ok
|
|
f() async { // //# 03: continued
|
|
assert(await new Future.microtask(() => true)); // //# 03: continued
|
|
return 42; // //# 03: continued
|
|
} // //# 03: continued
|
|
return expect42(f()); // //# 03: continued
|
|
}); // //# 03: continued
|
|
|
|
test("inside assert, false", () { // //# 03: continued
|
|
f() async { // //# 03: continued
|
|
assert(await new Future.microtask(() => false)); // //# 03: continued
|
|
return 42; // //# 03: continued
|
|
} // //# 03: continued
|
|
return f().then((_) { // //# 03: continued
|
|
fail("assert didn't throw"); // //# 03: continued
|
|
}, onError: (e, s) { // //# 03: continued
|
|
expect(e is AssertionError, isTrue); // //# 03: continued
|
|
}); // //# 03: continued
|
|
}); // //# 03: continued
|
|
|
|
test("inside assert, function -> false", () { // //# 03: continued
|
|
f() async { // //# 03: continued
|
|
assert(await new Future.microtask(() => false)); // //# 03: continued
|
|
return 42; // //# 03: continued
|
|
} // //# 03: continued
|
|
return f().then((_) { // //# 03: continued
|
|
fail("assert didn't throw"); // //# 03: continued
|
|
}, onError: (e, s) { // //# 03: continued
|
|
expect(e is AssertionError, isTrue); // //# 03: continued
|
|
}); // //# 03: continued
|
|
}); // //# 03: continued
|
|
});
|
|
|
|
group("syntax", () {
|
|
test("async as variable", () {
|
|
// Valid identifiers outside of async function.
|
|
var async = 42;
|
|
expect(async, equals(42));
|
|
});
|
|
|
|
test("await as variable", () { // //# 02: ok
|
|
// Valid identifiers outside of async function. // //# 02: continued
|
|
var await = 42; // //# 02: continued
|
|
expect(await, equals(42)); // //# 02: continued
|
|
}); // //# 02: continued
|
|
|
|
test("yield as variable", () {
|
|
// Valid identifiers outside of async function.
|
|
var yield = 42;
|
|
expect(yield, equals(42));
|
|
});
|
|
});
|
|
asyncEnd();
|
|
}
|
|
|
|
// Mock test framework sufficient to run tests.
|
|
|
|
String _currentName = "";
|
|
|
|
test(name, action()) {
|
|
var oldName = _currentName;
|
|
_currentName = [oldName, name].join(" ");
|
|
runZoned(() {
|
|
asyncTest(() => new Future.sync(action));
|
|
}, zoneValues: {#testName: _currentName});
|
|
_currentName = oldName;
|
|
}
|
|
|
|
group(name, entries()) {
|
|
var oldName = _currentName;
|
|
_currentName = [oldName, name].join(" ");
|
|
entries();
|
|
_currentName = oldName;
|
|
}
|
|
|
|
expect(value, expectation) {
|
|
var name = Zone.current[#testName];
|
|
if (expectation is bool) {
|
|
// Just for better error message.
|
|
(expectation ? Expect.isTrue : Expect.isFalse)(value, name);
|
|
return;
|
|
}
|
|
if (expectation is List) {
|
|
Expect.listEquals(expectation, value, name);
|
|
return;
|
|
}
|
|
if (expectation is Function(Object, String)) {
|
|
expectation(value, name);
|
|
return;
|
|
}
|
|
Expect.equals(expectation, value, name);
|
|
}
|
|
|
|
equals(x) => x;
|
|
final isTrue = true;
|
|
same(v) => (Object o, String name) => Expect.identical(v, o, name);
|
|
fail(message) {
|
|
var name = Zone.current[#testName];
|
|
Expect.fail("$name: $message");
|
|
}
|
|
|
|
// End mock.
|
|
|
|
// Attempt to obfuscates value to avoid too much constant folding.
|
|
id(v) {
|
|
try {
|
|
if (v != null) throw v;
|
|
} catch (e) {
|
|
return e;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Create a stream for testing "async for-in".
|
|
Stream<int> mkStream() {
|
|
StreamController<int> c;
|
|
int i = 0;
|
|
next() {
|
|
c.add(i++);
|
|
if (i == 10) {
|
|
c.close();
|
|
} else {
|
|
scheduleMicrotask(next);
|
|
}
|
|
}
|
|
|
|
c = new StreamController(onListen: () {
|
|
scheduleMicrotask(next);
|
|
});
|
|
return c.stream;
|
|
}
|
|
|
|
// Check that future contains the error "err".
|
|
Future throwsErr(Future future) {
|
|
return future.then((v) {
|
|
fail("didn't throw");
|
|
}, onError: (e) {
|
|
expect(e, equals("err"));
|
|
});
|
|
}
|
|
|
|
// Check that future contains the value 42.
|
|
Future expect42(Future future) {
|
|
return future.then((v) {
|
|
expect(v, equals(42));
|
|
});
|
|
}
|
|
|
|
// Various async declarations.
|
|
|
|
Future topMethod(f) async {
|
|
return await f;
|
|
}
|
|
|
|
Future topArrowMethod(f) async => await f;
|
|
|
|
Future get topGetter async {
|
|
return await new Future.value(42);
|
|
}
|
|
|
|
Future get topArrowGetter async => await new Future.value(42);
|
|
|
|
Future topLocal(f) {
|
|
local() async {
|
|
return await f;
|
|
}
|
|
|
|
return local();
|
|
}
|
|
|
|
Future topArrowLocal(f) {
|
|
local() async => await f;
|
|
return local();
|
|
}
|
|
|
|
Future topExpression(f) {
|
|
return () async {
|
|
return await f;
|
|
}();
|
|
}
|
|
|
|
Future topArrowExpression(f) {
|
|
return (() async => await f)();
|
|
}
|
|
|
|
DynamicToDynamic topVarExpression = (f) async {
|
|
return await f;
|
|
};
|
|
|
|
var topVarArrowExpression = (f) async => await f;
|
|
|
|
class Async {
|
|
var initValue;
|
|
Async();
|
|
|
|
Async.initializer(f)
|
|
: initValue = (() async {
|
|
return await f;
|
|
}());
|
|
|
|
Async.initializerArrow(f) : initValue = ((() async => await f)());
|
|
|
|
/* static */
|
|
static Future staticMethod(f) async {
|
|
return await f;
|
|
}
|
|
|
|
static Future staticArrowMethod(f) async => await f;
|
|
|
|
static Future get staticGetter async {
|
|
return await new Future.value(42);
|
|
}
|
|
|
|
static Future get staticArrowGetter async => await new Future.value(42);
|
|
|
|
static Future staticLocal(f) {
|
|
local() async {
|
|
return await f;
|
|
}
|
|
|
|
return local();
|
|
}
|
|
|
|
static Future staticArrowLocal(f) {
|
|
local() async => await f;
|
|
return local();
|
|
}
|
|
|
|
static Future staticExpression(f) {
|
|
return () async {
|
|
return await f;
|
|
}();
|
|
}
|
|
|
|
static Future staticArrowExpression(f) {
|
|
return (() async => await f)();
|
|
}
|
|
|
|
static DynamicToDynamic staticVarExpression = (f) async {
|
|
return await f;
|
|
};
|
|
|
|
static var staticVarArrowExpression = (f) async => await f;
|
|
|
|
/* instance */
|
|
Future instanceMethod(f) async {
|
|
return await f;
|
|
}
|
|
|
|
Future instanceArrowMethod(f) async => await f;
|
|
|
|
Future get instanceGetter async {
|
|
return await new Future.value(42);
|
|
}
|
|
|
|
Future get instanceArrowGetter async => await new Future.value(42);
|
|
|
|
Future instanceLocal(f) {
|
|
local() async {
|
|
return await f;
|
|
}
|
|
|
|
return local();
|
|
}
|
|
|
|
Future instanceArrowLocal(f) {
|
|
local() async => await f;
|
|
return local();
|
|
}
|
|
|
|
Future instanceExpression(f) {
|
|
return () async {
|
|
return await f;
|
|
}();
|
|
}
|
|
|
|
Future instanceArrowExpression(f) {
|
|
return (() async => await f)();
|
|
}
|
|
|
|
DynamicToDynamic instanceVarExpression = (f) async {
|
|
return await f;
|
|
};
|
|
|
|
var instanceVarArrowExpression = (f) async => await f;
|
|
}
|
|
|
|
Future asyncInAsync(f) async {
|
|
inner(f) async {
|
|
return await f;
|
|
}
|
|
|
|
return await inner(f);
|
|
}
|
|
|
|
Future asyncInSync(f) {
|
|
inner(f) async {
|
|
return await f;
|
|
}
|
|
|
|
return inner(f);
|
|
}
|
|
|
|
Future syncInAsync(f) async {
|
|
inner(f) {
|
|
return f;
|
|
}
|
|
|
|
return await inner(f);
|
|
}
|
|
|
|
/**
|
|
* A non-standard implementation of Future with a value.
|
|
*/
|
|
class FakeValueFuture implements Future {
|
|
final _value;
|
|
FakeValueFuture(this._value);
|
|
Future<S> then<S>(callback(value), {Function onError}) {
|
|
return new Future<S>.microtask(() => callback(_value));
|
|
}
|
|
|
|
Future whenComplete(callback()) {
|
|
return new Future.microtask(() {
|
|
callback();
|
|
});
|
|
}
|
|
|
|
Future catchError(Function onError, {bool test(error)}) => this;
|
|
Stream asStream() => (new StreamController()
|
|
..add(_value)
|
|
..close())
|
|
.stream;
|
|
Future timeout(Duration duration, {onTimeout()}) => this;
|
|
}
|
|
|
|
typedef OnErrorCallback2 = dynamic Function(Object, StackTrace);
|
|
typedef OnErrorCallback1 = dynamic Function(Object);
|
|
|
|
/**
|
|
* A non-standard implementation of Future with an error.
|
|
*/
|
|
class FakeErrorFuture implements Future {
|
|
final _error;
|
|
FakeErrorFuture(this._error);
|
|
Future<S> then<S>(callback(value), {Function onError}) {
|
|
if (onError != null) {
|
|
if (onError is OnErrorCallback2) {
|
|
return new Future<S>.microtask(() => onError(_error, StackTrace.empty));
|
|
} else if (onError is OnErrorCallback1) {
|
|
return new Future<S>.microtask(() => onError(_error));
|
|
} else {
|
|
throw new ArgumentError.value(
|
|
onError,
|
|
"onError",
|
|
"Error handler must accept one Object or one Object and a StackTrace"
|
|
" as arguments, and return a valid result");
|
|
}
|
|
}
|
|
return new Future<S>.error(_error);
|
|
}
|
|
|
|
Future whenComplete(callback()) {
|
|
return new Future.microtask(() {
|
|
callback();
|
|
}).then((_) => this);
|
|
}
|
|
|
|
Future catchError(Function onError, {bool test(error)}) {
|
|
return new Future.microtask(() {
|
|
if (test != null && !test(_error)) return this;
|
|
if (onError is OnErrorCallback2) {
|
|
return onError(_error, null);
|
|
} else if (onError is OnErrorCallback1) {
|
|
return onError(_error);
|
|
} else {
|
|
throw new ArgumentError.value(
|
|
onError,
|
|
"onError",
|
|
"Error handler must accept one Object or one Object and a StackTrace"
|
|
" as arguments, and return a valid result");
|
|
}
|
|
});
|
|
}
|
|
|
|
Stream asStream() => (new StreamController()
|
|
..addError(_error)
|
|
..close())
|
|
.stream;
|
|
Future timeout(Duration duration, {onTimeout()}) => this;
|
|
}
|