v8/test/mjsunit/harmony/async-generators-basic.js

1754 lines
56 KiB
JavaScript
Raw Normal View History

[async-iteration] implement AsyncGenerator - Introduce new struct AsyncGeneratorRequest, which holds information pertinent to resuming execution of an AsyncGenerator, such as the Promise associated with the async generator request. It is intended to be used as a singly linked list, and holds a pointer to the next item in te queue. - Introduce JSAsyncGeneratorObject (subclass of JSGeneratorObject), which includes several new internal fields (`queue` which contains a singly linked list of AsyncGeneratorRequest objects, and `await_input` which contains the sent value from an Await expression (This is necessary to prevent function.sent (used by yield*) from having the sent value observably overwritten during execution). - Modify SuspendGenerator to accept a set of Flags, which indicate whether the suspend is for a Yield or Await, and whether it takes place on an async generator or ES6 generator. - Introduce interpreter intrinsics and TF intrinsic lowering for accessing the await input of an async generator - Modify the JSGeneratorStore operator to understand whether or not it's suspending for a normal yield, or an AsyncGenerator Await. This ensures appropriate registers are stored. - Add versions of ResumeGeneratorTrampoline which store the input value in a different field depending on wether it's an AsyncGenerator Await resume, or an ordinary resume. Also modifies whether debug code will assert that the generator object is a JSGeneratorObject or a JSAsyncGeneratorObject depending on the resume type. BUG=v8:5855 R=bmeurer@chromium.org, rmcilroy@chromium.org, jgruber@chromium.org, littledan@chromium.org, neis@chromium.org TBR=marja@chromium.org Change-Id: I9d58df1d344465fc937fe7eed322424204497187 Reviewed-on: https://chromium-review.googlesource.com/446961 Commit-Queue: Caitlin Potter <caitp@igalia.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#44240}
2017-03-29 13:41:45 +00:00
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
[async-iteration] implement AsyncGenerator - Introduce new struct AsyncGeneratorRequest, which holds information pertinent to resuming execution of an AsyncGenerator, such as the Promise associated with the async generator request. It is intended to be used as a singly linked list, and holds a pointer to the next item in te queue. - Introduce JSAsyncGeneratorObject (subclass of JSGeneratorObject), which includes several new internal fields (`queue` which contains a singly linked list of AsyncGeneratorRequest objects, and `await_input` which contains the sent value from an Await expression (This is necessary to prevent function.sent (used by yield*) from having the sent value observably overwritten during execution). - Modify SuspendGenerator to accept a set of Flags, which indicate whether the suspend is for a Yield or Await, and whether it takes place on an async generator or ES6 generator. - Introduce interpreter intrinsics and TF intrinsic lowering for accessing the await input of an async generator - Modify the JSGeneratorStore operator to understand whether or not it's suspending for a normal yield, or an AsyncGenerator Await. This ensures appropriate registers are stored. - Add versions of ResumeGeneratorTrampoline which store the input value in a different field depending on wether it's an AsyncGenerator Await resume, or an ordinary resume. Also modifies whether debug code will assert that the generator object is a JSGeneratorObject or a JSAsyncGeneratorObject depending on the resume type. BUG=v8:5855 R=bmeurer@chromium.org, rmcilroy@chromium.org, jgruber@chromium.org, littledan@chromium.org, neis@chromium.org TBR=marja@chromium.org Change-Id: I9d58df1d344465fc937fe7eed322424204497187 Reviewed-on: https://chromium-review.googlesource.com/446961 Commit-Queue: Caitlin Potter <caitp@igalia.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#44240}
2017-03-29 13:41:45 +00:00
function assertThrowsAsync(run, errorType, message) {
var actual;
var hadValue = false;
var hadError = false;
var promise = run();
if (typeof promise !== "object" || typeof promise.then !== "function") {
throw new MjsUnitAssertionError(
`Expected ${run.toString()} to return a Promise, but it returned ` +
PrettyPrint(promise));
}
promise.then(function(value) { hadValue = true; actual = value; },
function(error) { hadError = true; actual = error; });
assertFalse(hadValue || hadError);
%RunMicrotasks();
if (!hadError) {
throw new MjsUnitAssertionError(
"Expected " + run + "() to throw " + errorType.name +
", but did not throw.");
}
if (!(actual instanceof errorType))
throw new MjsUnitAssertionError(
"Expected " + run + "() to throw " + errorType.name +
", but threw '" + actual + "'");
if (message !== void 0 && actual.message !== message)
throw new MjsUnitAssertionError(
"Expected " + run + "() to throw '" + message + "', but threw '" +
actual.message + "'");
};
function assertEqualsAsync(expected, run, msg) {
var actual;
var hadValue = false;
var hadError = false;
var promise = run();
if (typeof promise !== "object" || typeof promise.then !== "function") {
throw new MjsUnitAssertionError(
`Expected ${run.toString()} to return a Promise, but it returned ` +
`${promise}`);
}
promise.then(function(value) { hadValue = true; actual = value; },
function(error) { hadError = true; actual = error; });
assertFalse(hadValue || hadError);
%RunMicrotasks();
if (hadError) throw actual;
assertTrue(
hadValue, "Expected '" + run.toString() + "' to produce a value");
assertEquals(expected, actual, msg);
};
class MyError extends Error {};
function Thrower(msg) { throw new MyError(msg); }
function Rejecter(msg) {
return new Promise(function(resolve, reject) {
Promise.resolve().then(function() {
reject(new MyError(msg));
});
});
}
function Resolver(msg) {
return new Promise(function(resolve, reject) {
Promise.resolve().then(function() {
resolve(msg);
});
});
}
async function ForAwaitOfValues(it) {
let array = [];
for await (let x of it) array.push(x);
return array;
}
let log = [];
function logIterResult(iter_result) {
log.push(iter_result);
}
function logError(error) {
log.push(error);
}
function AbortUnreachable() {
%AbortJS("This code should not be reachable.");
}
// ----------------------------------------------------------------------------
// Do not install `AsyncGeneratorFunction` constructor on global object
assertEquals(undefined, this.AsyncGeneratorFunction);
// ----------------------------------------------------------------------------
let AsyncGenerator = Object.getPrototypeOf(async function*() {});
let AsyncGeneratorPrototype = AsyncGenerator.prototype;
// %AsyncGenerator% and %AsyncGeneratorPrototype% are both ordinary objects
assertEquals("object", typeof AsyncGenerator);
assertEquals("object", typeof AsyncGeneratorPrototype);
// %AsyncGenerator% <---> %AsyncGeneratorPrototype% circular reference
assertEquals(AsyncGenerator, AsyncGeneratorPrototype.constructor);
assertEquals(AsyncGeneratorPrototype, AsyncGenerator.prototype);
let protoDesc = Object.getOwnPropertyDescriptor(AsyncGenerator, 'prototype');
assertFalse(protoDesc.enumerable);
assertFalse(protoDesc.writable);
assertTrue(protoDesc.configurable);
let ctorDesc =
Object.getOwnPropertyDescriptor(AsyncGeneratorPrototype, 'constructor');
assertFalse(ctorDesc.enumerable);
assertFalse(ctorDesc.writable);
assertTrue(ctorDesc.configurable);
[async-iteration] implement AsyncGenerator - Introduce new struct AsyncGeneratorRequest, which holds information pertinent to resuming execution of an AsyncGenerator, such as the Promise associated with the async generator request. It is intended to be used as a singly linked list, and holds a pointer to the next item in te queue. - Introduce JSAsyncGeneratorObject (subclass of JSGeneratorObject), which includes several new internal fields (`queue` which contains a singly linked list of AsyncGeneratorRequest objects, and `await_input` which contains the sent value from an Await expression (This is necessary to prevent function.sent (used by yield*) from having the sent value observably overwritten during execution). - Modify SuspendGenerator to accept a set of Flags, which indicate whether the suspend is for a Yield or Await, and whether it takes place on an async generator or ES6 generator. - Introduce interpreter intrinsics and TF intrinsic lowering for accessing the await input of an async generator - Modify the JSGeneratorStore operator to understand whether or not it's suspending for a normal yield, or an AsyncGenerator Await. This ensures appropriate registers are stored. - Add versions of ResumeGeneratorTrampoline which store the input value in a different field depending on wether it's an AsyncGenerator Await resume, or an ordinary resume. Also modifies whether debug code will assert that the generator object is a JSGeneratorObject or a JSAsyncGeneratorObject depending on the resume type. BUG=v8:5855 R=bmeurer@chromium.org, rmcilroy@chromium.org, jgruber@chromium.org, littledan@chromium.org, neis@chromium.org TBR=marja@chromium.org Change-Id: I9d58df1d344465fc937fe7eed322424204497187 Reviewed-on: https://chromium-review.googlesource.com/446961 Commit-Queue: Caitlin Potter <caitp@igalia.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#44240}
2017-03-29 13:41:45 +00:00
// ----------------------------------------------------------------------------
// The AsyncGeneratorFunction Constructor is the %AsyncGeneratorFunction%
// intrinsic object and is a subclass of Function.
// (proposal-async-iteration/#sec-asyncgeneratorfunction-constructor)
let AsyncGeneratorFunction = AsyncGenerator.constructor;
[async-iteration] implement AsyncGenerator - Introduce new struct AsyncGeneratorRequest, which holds information pertinent to resuming execution of an AsyncGenerator, such as the Promise associated with the async generator request. It is intended to be used as a singly linked list, and holds a pointer to the next item in te queue. - Introduce JSAsyncGeneratorObject (subclass of JSGeneratorObject), which includes several new internal fields (`queue` which contains a singly linked list of AsyncGeneratorRequest objects, and `await_input` which contains the sent value from an Await expression (This is necessary to prevent function.sent (used by yield*) from having the sent value observably overwritten during execution). - Modify SuspendGenerator to accept a set of Flags, which indicate whether the suspend is for a Yield or Await, and whether it takes place on an async generator or ES6 generator. - Introduce interpreter intrinsics and TF intrinsic lowering for accessing the await input of an async generator - Modify the JSGeneratorStore operator to understand whether or not it's suspending for a normal yield, or an AsyncGenerator Await. This ensures appropriate registers are stored. - Add versions of ResumeGeneratorTrampoline which store the input value in a different field depending on wether it's an AsyncGenerator Await resume, or an ordinary resume. Also modifies whether debug code will assert that the generator object is a JSGeneratorObject or a JSAsyncGeneratorObject depending on the resume type. BUG=v8:5855 R=bmeurer@chromium.org, rmcilroy@chromium.org, jgruber@chromium.org, littledan@chromium.org, neis@chromium.org TBR=marja@chromium.org Change-Id: I9d58df1d344465fc937fe7eed322424204497187 Reviewed-on: https://chromium-review.googlesource.com/446961 Commit-Queue: Caitlin Potter <caitp@igalia.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#44240}
2017-03-29 13:41:45 +00:00
assertEquals(Object.getPrototypeOf(AsyncGeneratorFunction), Function);
assertEquals(Object.getPrototypeOf(AsyncGeneratorFunction.prototype),
Function.prototype);
assertTrue(async function*() {} instanceof Function);
// ----------------------------------------------------------------------------
// Let functionPrototype be the intrinsic object %AsyncGeneratorPrototype%.
async function* asyncGeneratorForProto() {}
assertEquals(AsyncGeneratorFunction.prototype,
Object.getPrototypeOf(asyncGeneratorForProto));
assertEquals(AsyncGeneratorFunction.prototype,
Object.getPrototypeOf(async function*() {}));
assertEquals(AsyncGeneratorFunction.prototype,
Object.getPrototypeOf({ async* method() {} }.method));
assertEquals(AsyncGeneratorFunction.prototype,
Object.getPrototypeOf(AsyncGeneratorFunction()));
assertEquals(AsyncGeneratorFunction.prototype,
Object.getPrototypeOf(new AsyncGeneratorFunction()));
// ----------------------------------------------------------------------------
// AsyncGeneratorFunctionCreate produces a function whose prototype property is
// derived from %AsyncGeneratorPrototype%
assertEquals(AsyncGeneratorFunction.prototype.prototype,
Object.getPrototypeOf(asyncGeneratorForProto.prototype));
assertTrue(asyncGeneratorForProto.hasOwnProperty("prototype"));
assertEquals(AsyncGeneratorFunction.prototype.prototype,
Object.getPrototypeOf((async function*() {}).prototype));
assertTrue((async function*() {}).hasOwnProperty("prototype"));
assertEquals(AsyncGeneratorFunction.prototype.prototype,
Object.getPrototypeOf(({ async* method() {} }).method.prototype));
assertTrue(({ async* method() {} }).method.hasOwnProperty("prototype"));
assertEquals(AsyncGeneratorFunction.prototype.prototype,
Object.getPrototypeOf(AsyncGeneratorFunction().prototype));
assertTrue(AsyncGeneratorFunction().hasOwnProperty("prototype"));
assertEquals(AsyncGeneratorFunction.prototype.prototype,
Object.getPrototypeOf(new AsyncGeneratorFunction().prototype));
assertTrue(new AsyncGeneratorFunction().hasOwnProperty("prototype"));
// ----------------------------------------------------------------------------
// Basic Function.prototype.toString()
async function* asyncGeneratorForToString() {}
assertEquals("async function* asyncGeneratorForToString() {}",
asyncGeneratorForToString.toString());
assertEquals("async function*() {}", async function*() {}.toString());
assertEquals("async function* namedAsyncGeneratorForToString() {}",
async function* namedAsyncGeneratorForToString() {}.toString());
assertEquals("async *method() { }",
({ async *method() { } }).method.toString());
assertEquals("async *method() { }",
(class { static async *method() { } }).method.toString());
assertEquals("async *method() { }",
(new (class { async *method() { } })).method.toString());
assertEquals("async function* anonymous(\n) {\n\n}",
AsyncGeneratorFunction().toString());
assertEquals("async function* anonymous(\n) {\n\n}",
(new AsyncGeneratorFunction()).toString());
[async-iteration] implement AsyncGenerator - Introduce new struct AsyncGeneratorRequest, which holds information pertinent to resuming execution of an AsyncGenerator, such as the Promise associated with the async generator request. It is intended to be used as a singly linked list, and holds a pointer to the next item in te queue. - Introduce JSAsyncGeneratorObject (subclass of JSGeneratorObject), which includes several new internal fields (`queue` which contains a singly linked list of AsyncGeneratorRequest objects, and `await_input` which contains the sent value from an Await expression (This is necessary to prevent function.sent (used by yield*) from having the sent value observably overwritten during execution). - Modify SuspendGenerator to accept a set of Flags, which indicate whether the suspend is for a Yield or Await, and whether it takes place on an async generator or ES6 generator. - Introduce interpreter intrinsics and TF intrinsic lowering for accessing the await input of an async generator - Modify the JSGeneratorStore operator to understand whether or not it's suspending for a normal yield, or an AsyncGenerator Await. This ensures appropriate registers are stored. - Add versions of ResumeGeneratorTrampoline which store the input value in a different field depending on wether it's an AsyncGenerator Await resume, or an ordinary resume. Also modifies whether debug code will assert that the generator object is a JSGeneratorObject or a JSAsyncGeneratorObject depending on the resume type. BUG=v8:5855 R=bmeurer@chromium.org, rmcilroy@chromium.org, jgruber@chromium.org, littledan@chromium.org, neis@chromium.org TBR=marja@chromium.org Change-Id: I9d58df1d344465fc937fe7eed322424204497187 Reviewed-on: https://chromium-review.googlesource.com/446961 Commit-Queue: Caitlin Potter <caitp@igalia.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#44240}
2017-03-29 13:41:45 +00:00
// ----------------------------------------------------------------------------
// AsyncGenerator functions syntactically allow AwaitExpressions
assertEquals(1, async function*(a) { await 1; }.length);
assertEquals(2, async function*(a, b) { await 1; }.length);
assertEquals(1, async function*(a, b = 2) { await 1; }.length);
assertEquals(2, async function*(a, b, ...c) { await 1; }.length);
assertEquals(1, ({ async* f(a) { await 1; } }).f.length);
assertEquals(2, ({ async* f(a, b) { await 1; } }).f.length);
assertEquals(1, ({ async* f(a, b = 2) { await 1; } }).f.length);
assertEquals(2, ({ async* f(a, b, ...c) { await 1; } }).f.length);
assertEquals(1, AsyncGeneratorFunction("a", "await 1").length);
assertEquals(2, AsyncGeneratorFunction("a", "b", "await 1").length);
assertEquals(1, AsyncGeneratorFunction("a", "b = 2", "await 1").length);
assertEquals(2, AsyncGeneratorFunction("a", "b", "...c", "await 1").length);
assertEquals(1, (new AsyncGeneratorFunction("a", "await 1")).length);
assertEquals(2, (new AsyncGeneratorFunction("a", "b", "await 1")).length);
assertEquals(1, (new AsyncGeneratorFunction("a", "b = 2", "await 1")).length);
assertEquals(2,
(new AsyncGeneratorFunction("a", "b", "...c", "await 1")).length);
// ----------------------------------------------------------------------------
// AsyncGenerator functions syntactically allow YieldExpressions
assertEquals(1, async function*(a) { yield 1; }.length);
assertEquals(2, async function*(a, b) { yield 1; }.length);
assertEquals(1, async function*(a, b = 2) { yield 1; }.length);
assertEquals(2, async function*(a, b, ...c) { yield 1; }.length);
assertEquals(1, ({ async* f(a) { yield 1; } }).f.length);
assertEquals(2, ({ async* f(a, b) { yield 1; } }).f.length);
assertEquals(1, ({ async* f(a, b = 2) { yield 1; } }).f.length);
assertEquals(2, ({ async* f(a, b, ...c) { yield 1; } }).f.length);
assertEquals(1, AsyncGeneratorFunction("a", "yield 1").length);
assertEquals(2, AsyncGeneratorFunction("a", "b", "yield 1").length);
assertEquals(1, AsyncGeneratorFunction("a", "b = 2", "yield 1").length);
assertEquals(2, AsyncGeneratorFunction("a", "b", "...c", "yield 1").length);
assertEquals(1, (new AsyncGeneratorFunction("a", "yield 1")).length);
assertEquals(2, (new AsyncGeneratorFunction("a", "b", "yield 1")).length);
assertEquals(1, (new AsyncGeneratorFunction("a", "b = 2", "yield 1")).length);
assertEquals(2,
(new AsyncGeneratorFunction("a", "b", "...c", "yield 1")).length);
// ----------------------------------------------------------------------------
// AsyncGeneratorFunction.prototype[ @@toStringTag ]
var descriptor =
Object.getOwnPropertyDescriptor(AsyncGeneratorFunction.prototype,
Symbol.toStringTag);
assertEquals("AsyncGeneratorFunction", descriptor.value);
assertEquals(false, descriptor.enumerable);
assertEquals(false, descriptor.writable);
assertEquals(true, descriptor.configurable);
assertEquals(1, AsyncGeneratorFunction.length);
// ----------------------------------------------------------------------------
// Let F be ! FunctionAllocate(functionPrototype, Strict, "non-constructor")
async function* asyncNonConstructorDecl() {}
assertThrows(() => new asyncNonConstructorDecl(), TypeError);
assertThrows(() => asyncNonConstructorDecl.caller, TypeError);
assertThrows(() => asyncNonConstructorDecl.arguments, TypeError);
assertThrows(() => new (async function*() {}), TypeError);
assertThrows(() => (async function*() {}).caller, TypeError);
assertThrows(() => (async function*() {}).arguments, TypeError);
assertThrows(
() => new ({ async* nonConstructor() {} }).nonConstructor(), TypeError);
assertThrows(
() => ({ async* nonConstructor() {} }).nonConstructor.caller, TypeError);
assertThrows(
() => ({ async* nonConstructor() {} }).nonConstructor.arguments, TypeError);
assertThrows(
() => new (AsyncGeneratorFunction("nonconstructor"))(), TypeError);
assertThrows(
() => AsyncGeneratorFunction("nonconstructor").caller, TypeError);
assertThrows(
() => AsyncGeneratorFunction("nonconstructor").arguments, TypeError);
assertThrows(
() => new (new AsyncGeneratorFunction("nonconstructor"))(), TypeError);
assertThrows(
() => (new AsyncGeneratorFunction("nonconstructor")).caller, TypeError);
assertThrows(
() => (new AsyncGeneratorFunction("nonconstructor")).arguments, TypeError);
// ----------------------------------------------------------------------------
// Empty functions
async function* emptyAsyncGenerator() {}
let it = emptyAsyncGenerator();
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function* emptyAsyncGeneratorExpr() { })();
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({ async* method() { } }).method();
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = AsyncGeneratorFunction(``)();
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(``))();
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level ReturnStatement
async function* asyncGeneratorForReturn() {
return "boop1";
throw "(unreachble)";
}
it = asyncGeneratorForReturn();
assertEqualsAsync({ value: "boop1", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
return "boop2";
throw "(unreachable)";
})();
assertEqualsAsync({ value: "boop2", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({ async* method() { return "boop3"; throw "(unreachable)"; } }).method();
assertEqualsAsync({ value: "boop3", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = AsyncGeneratorFunction(`
return "boop4";
throw "(unreachable)";`)();
assertEqualsAsync({ value: "boop4", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
return "boop5";
throw "(unreachable)";`))();
assertEqualsAsync({ value: "boop5", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level ReturnStatement after await
async function* asyncGeneratorForReturnAfterAwait() {
await 1;
return "boop6";
throw "(unreachable)";
}
it = asyncGeneratorForReturnAfterAwait();
assertEqualsAsync({ value: "boop6", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() { await 1; return "boop7"; throw "(unreachable)"; })();
assertEqualsAsync({ value: "boop7", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
await 1;
return "boop8";
throw "(unreachable)";
}
}).method();
assertEqualsAsync({ value: "boop8", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = AsyncGeneratorFunction(`
await 1;
return "boop9";
throw "(unreachable)"`)();
assertEqualsAsync({ value: "boop9", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
await 1;
return "boop10";
throw "(unreachable)"`))();
assertEqualsAsync({ value: "boop10", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level Yields
async function* asyncGeneratorForYields() {
yield 1;
yield await Resolver(2);
yield Resolver(3);
return 4;
throw "(unreachable)";
}
it = asyncGeneratorForYields();
assertEqualsAsync([1, 2, 3], () => ForAwaitOfValues(it));
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
yield "cow";
yield await Resolver("bird");
yield await "dog";
yield Resolver("donkey");
return "badger";
throw "(unreachable)"; })();
assertEqualsAsync(["cow", "bird", "dog", "donkey"], () => ForAwaitOfValues(it));
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
yield "A";
yield await Resolver("B");
yield await "C";
yield Resolver("CC");
return "D";
throw "(unreachable)";
}
}).method();
assertEqualsAsync(["A", "B", "C", "CC"], () => ForAwaitOfValues(it));
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = AsyncGeneratorFunction(`
yield "alpha";
yield await Resolver("beta");
yield await "gamma";
yield Resolver("delta");
return "epsilon";
throw "(unreachable)"`)();
assertEqualsAsync(["alpha", "beta", "gamma", "delta"],
() => ForAwaitOfValues(it));
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
yield "α";
yield await Resolver("β");
yield await "γ";
yield Resolver("δ");
return "ε";
throw "(unreachable)"`))();
assertEqualsAsync(["α", "β", "γ", "δ"], () => ForAwaitOfValues(it));
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Nested Resume via [AsyncGenerator].next()
log = [];
async function* asyncGeneratorForNestedResumeNext() {
it.next().then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "rootbeer";
yield await Resolver("float");
}
it = asyncGeneratorForNestedResumeNext();
it.next().then(logIterResult, AbortUnreachable);
%RunMicrotasks();
assertEquals([
{ value: "rootbeer", done: false },
{ value: "float", done: false },
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorExprForNestedResumeNext = async function*() {
it.next().then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "first";
yield await Resolver("second");
};
it = asyncGeneratorExprForNestedResumeNext();
it.next().then(logIterResult, AbortUnreachable);
%RunMicrotasks();
assertEquals([
{ value: "first", done: false },
{ value: "second", done: false },
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorMethodForNestedResumeNext = ({
async* method() {
it.next().then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "remember";
yield await Resolver("the cant!");
}
}).method;
it = asyncGeneratorMethodForNestedResumeNext();
it.next().then(logIterResult, AbortUnreachable);
%RunMicrotasks();
assertEquals([
{ value: "remember", done: false },
{ value: "the cant!", done: false },
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorCallEvalForNestedResumeNext =
AsyncGeneratorFunction(`
it.next().then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "reading";
yield await Resolver("rainbow!");`);
it = asyncGeneratorCallEvalForNestedResumeNext();
it.next().then(logIterResult, AbortUnreachable);
%RunMicrotasks();
assertEquals([
{ value: "reading", done: false },
{ value: "rainbow!", done: false },
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorNewEvalForNestedResumeNext =
new AsyncGeneratorFunction(`
it.next().then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield 731;
yield await Resolver("BB!");`);
it = asyncGeneratorNewEvalForNestedResumeNext();
it.next().then(logIterResult, AbortUnreachable);
%RunMicrotasks();
assertEquals([
{ value: 731, done: false },
{ value: "BB!", done: false },
{ value: undefined, done: true }
], log);
// ----------------------------------------------------------------------------
// Nested Resume via [AsyncGenerator].throw()
log = [];
async function* asyncGeneratorForNestedResumeThrow() {
try {
it.throw(await Rejecter("...")).then(logIterResult, logError);
} catch (e) {
it.throw("throw2").then(logIterResult, logError);
it.next().then(logIterResult, logError);
throw "throw1";
}
AbortUnreachable();
}
it = asyncGeneratorForNestedResumeThrow();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
"throw1",
"throw2",
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorExprForNestedResumeThrow = async function*() {
try {
it.throw(await Rejecter("...")).then(logIterResult, logError);
} catch (e) {
it.throw("throw4").then(logIterResult, logError);
it.next().then(logIterResult, logError);
throw "throw3";
}
AbortUnreachable();
};
it = asyncGeneratorExprForNestedResumeThrow();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
"throw3",
"throw4",
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorMethodForNestedResumeThrow = ({
async* method() {
try {
it.throw(await Rejecter("...")).then(logIterResult, logError);
} catch (e) {
it.throw("throw6").then(logIterResult, logError);
it.next().then(logIterResult, logError);
throw "throw5";
}
AbortUnreachable();
}
}).method;
it = asyncGeneratorMethodForNestedResumeThrow();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
"throw5",
"throw6",
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorCallEvalForNestedResumeThrow =
AsyncGeneratorFunction(`
try {
it.throw(await Rejecter("...")).then(logIterResult, logError);
} catch (e) {
it.throw("throw8").then(logIterResult, logError);
it.next().then(logIterResult, logError);
throw "throw7";
}
AbortUnreachable();`);
it = asyncGeneratorCallEvalForNestedResumeThrow();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
"throw7",
"throw8",
{ value: undefined, done: true }
], log);
log = [];
let asyncGeneratorNewEvalForNestedResumeThrow =
new AsyncGeneratorFunction(`
try {
it.throw(await Rejecter("...")).then(logIterResult, logError);
} catch (e) {
it.throw("throw10").then(logIterResult, logError);
it.next().then(logIterResult, logError);
throw "throw9";
}
AbortUnreachable();`);
it = asyncGeneratorNewEvalForNestedResumeThrow();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
"throw9",
"throw10",
{ value: undefined, done: true }
], log);
// ----------------------------------------------------------------------------
// Nested Resume via [AsyncGenerator].return()
log = [];
async function* asyncGeneratorForNestedResumeReturn() {
it.return("step2").then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "step1";
AbortUnreachable();
}
it = asyncGeneratorForNestedResumeReturn();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
{ value: "step1", done: false },
{ value: "step2", done: true },
{ value: undefined, done: true },
], log);
log = [];
let asyncGeneratorExprForNestedResumeReturn = async function*() {
it.return("step4").then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "step3";
};
it = asyncGeneratorExprForNestedResumeReturn();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
{ value: "step3", done: false },
{ value: "step4", done: true },
{ value: undefined, done: true },
], log);
log = [];
let asyncGeneratorMethodForNestedResumeReturn = ({
async* method() {
it.return("step6").then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "step5";
}
}).method;
it = asyncGeneratorMethodForNestedResumeReturn();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
{ value: "step5", done: false },
{ value: "step6", done: true },
{ value: undefined, done: true },
], log);
log = [];
let asyncGeneratorCallEvalForNestedResumeReturn =
AsyncGeneratorFunction(`
it.return("step8").then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "step7";`);
it = asyncGeneratorCallEvalForNestedResumeReturn();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
{ value: "step7", done: false },
{ value: "step8", done: true },
{ value: undefined, done: true },
], log);
log = [];
let asyncGeneratorNewEvalForNestedResumeReturn =
new AsyncGeneratorFunction(`
it.return("step10").then(logIterResult, logError);
it.next().then(logIterResult, logError);
yield "step9";`);
it = asyncGeneratorNewEvalForNestedResumeReturn();
it.next().then(logIterResult, logError);
%RunMicrotasks();
assertEquals([
{ value: "step9", done: false },
{ value: "step10", done: true },
{ value: undefined, done: true },
], log);
// ----------------------------------------------------------------------------
// Top-level Yield ThrowStatement
async function* asyncGeneratorForYieldThrow() {
yield await Thrower("OOPS1");
throw "(unreachable)";
}
it = asyncGeneratorForYieldThrow();
assertThrowsAsync(() => it.next(), MyError, "OOPS1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() { yield Thrower("OOPS2"); throw "(unreachable)"; })();
assertThrowsAsync(() => it.next(), MyError, "OOPS2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
yield Thrower("OOPS3");
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "OOPS3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = AsyncGeneratorFunction(`
yield Thrower("OOPS4");
throw "(unreachable)"`)();
assertThrowsAsync(() => it.next(), MyError, "OOPS4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
yield Thrower("OOPS5");
throw "(unreachable)"`))();
assertThrowsAsync(() => it.next(), MyError, "OOPS5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level Yield Awaited Rejection
async function* asyncGeneratorForYieldAwaitedRejection() {
yield await Rejecter("OOPS1");
throw "(unreachable)";
}
it = asyncGeneratorForYieldAwaitedRejection();
assertThrowsAsync(() => it.next(), MyError, "OOPS1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
yield await Rejecter("OOPS2");
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "OOPS2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
yield await Rejecter("OOPS3");
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "OOPS3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = AsyncGeneratorFunction(`
yield await Rejecter("OOPS4");
throw "(unreachable)"`)();
assertThrowsAsync(() => it.next(), MyError, "OOPS4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
yield await Rejecter("OOPS5");
throw "(unreachable)"`))();
assertThrowsAsync(() => it.next(), MyError, "OOPS5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level ThrowStatement
async function* asyncGeneratorForThrow() {
throw new MyError("BOOM1");
throw "(unreachable)";
}
it = asyncGeneratorForThrow();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
throw new MyError("BOOM2");
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
throw new MyError("BOOM3");
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
throw new MyError("BOOM4");
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
throw new MyError("BOOM5");
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level ThrowStatement after Await
async function* asyncGeneratorForThrowAfterAwait() {
await 1;
throw new MyError("BOOM6");
throw "(unreachable)";
}
it = asyncGeneratorForThrowAfterAwait();
assertThrowsAsync(() => it.next(), MyError, "BOOM6");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
await 1;
throw new MyError("BOOM7");
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM7");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
await 1;
throw new MyError("BOOM8");
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM8");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
await 1;
throw new MyError("BOOM9");
throw "(unreachable)";`))();
assertThrowsAsync(() => it.next(), MyError, "BOOM9");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
await 1;
throw new MyError("BOOM10");
throw "(unreachable)";`))();
assertThrowsAsync(() => it.next(), MyError, "BOOM10");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Top-level Awaited rejection
async function* asyncGeneratorForAwaitedRejection() {
await Rejecter("BOOM11");
throw "(unreachable)";
}
it = asyncGeneratorForAwaitedRejection();
assertThrowsAsync(() => it.next(), MyError, "BOOM11");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
await Rejecter("BOOM12");
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM12");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
await Rejecter("BOOM13");
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM13");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
await Rejecter("BOOM14");
throw "(unreachable)";`))();
assertThrowsAsync(() => it.next(), MyError, "BOOM14");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (new AsyncGeneratorFunction(`
await Rejecter("BOOM15");
throw "(unreachable)";`))();
assertThrowsAsync(() => it.next(), MyError, "BOOM15");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Caught ThrowStatement
async function* asyncGeneratorForCaughtThrow() {
try {
throw new MyError("BOOM1");
} catch (e) {
return "caught1";
}
throw "(unreachable)";
}
it = asyncGeneratorForCaughtThrow();
assertEqualsAsync({ value: "caught1", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
throw new MyError("BOOM2");
} catch (e) {
return "caught2";
}
throw "(unreachable)";
})();
assertEqualsAsync({ value: "caught2", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
throw new MyError("BOOM3");
} catch (e) {
return "caught3";
}
throw "(unreachable)";
}
}).method();
assertEqualsAsync({ value: "caught3", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("BOOM4");
} catch (e) {
return "caught4";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "caught4", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("BOOM5");
} catch (e) {
return "caught5";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "caught5", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Caught ThrowStatement and rethrow
async function* asyncGeneratorForCaughtRethrow() {
try {
throw new MyError("BOOM1");
} catch (e) {
throw new MyError("RETHROW1");
}
throw "(unreachable)";
}
it = asyncGeneratorForCaughtRethrow();
assertThrowsAsync(() => it.next(), MyError, "RETHROW1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
throw new MyError("BOOM2");
} catch (e) {
throw new MyError("RETHROW2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "RETHROW2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
throw new MyError("BOOM3");
} catch (e) {
throw new MyError("RETHROW3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "RETHROW3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("BOOM4");
} catch (e) {
throw new MyError("RETHROW4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "RETHROW4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("BOOM5");
} catch (e) {
throw new MyError("RETHROW5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "RETHROW5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// ReturnStatement in Try, ReturnStatement in Finally
async function* asyncGeneratorForReturnInTryReturnInFinally() {
try {
return "early1"
} finally {
return "later1";
}
throw "(unreachable)";
}
it = asyncGeneratorForReturnInTryReturnInFinally();
assertEqualsAsync({ value: "later1", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
return "early2";
} finally {
return "later2";
}
throw "(unreachable)";
})();
assertEqualsAsync({ value: "later2", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
return "early3";
} finally {
return "later3";
}
throw "(unreachable)";
}
}).method();
assertEqualsAsync({ value: "later3", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
return "early4";
} finally {
return "later4";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "later4", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
return "early5";
} finally {
return "later5";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "later5", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// ThrowStatement in Try, ReturnStatement in Finally
async function* asyncGeneratorForThrowInTryReturnInFinally() {
try {
throw new MyError("BOOM1");
} finally {
return "later1";
}
throw "(unreachable)";
}
it = asyncGeneratorForThrowInTryReturnInFinally();
assertEqualsAsync({ value: "later1", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
throw new MyError("BOOM2");
} finally {
return "later2";
}
throw "(unreachable)";
})();
assertEqualsAsync({ value: "later2", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
throw new MyError("BOOM3");
} finally {
return "later3";
}
throw "(unreachable)";
}
}).method();
assertEqualsAsync({ value: "later3", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("BOOM4");
} finally {
return "later4";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "later4", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("BOOM5");
} finally {
return "later5";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "later5", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Awaited Rejection in Try, ReturnStatement in Finally
async function* asyncGeneratorForAwaitRejectionInTryReturnInFinally() {
try {
await Rejecter("BOOM1");
} finally {
return "later1";
}
throw "(unreachable)";
}
it = asyncGeneratorForThrowInTryReturnInFinally();
assertEqualsAsync({ value: "later1", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
await Rejecter("BOOM2");
} finally {
return "later2";
}
throw "(unreachable)";
})();
assertEqualsAsync({ value: "later2", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
await Rejecter("BOOM3");
} finally {
return "later3";
}
throw "(unreachable)";
}
}).method();
assertEqualsAsync({ value: "later3", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
await Rejecter("BOOM4");
} finally {
return "later4";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "later4", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
await Rejecter("BOOM5");
} finally {
return "later5";
}
throw "(unreachable)";`))()
assertEqualsAsync({ value: "later5", done: true }, () => it.next());
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// ReturnStatement in Try, ThrowStatement in Finally
async function* asyncGeneratorForReturnInTryThrowInFinally() {
try {
return "early1"
} finally {
throw new MyError("BOOM1");
}
throw "(unreachable)";
}
it = asyncGeneratorForReturnInTryThrowInFinally();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
return "early2";
} finally {
throw new MyError("BOOM2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
return "early3";
} finally {
throw new MyError("BOOM3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
return "early4";
} finally {
throw new MyError("BOOM4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
return "early5";
} finally {
throw new MyError("BOOM5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// ThrowStatement in Try, ThrowStatement in Finally
async function* asyncGeneratorForThrowInTryThrowInFinally() {
try {
throw new MyError("EARLY1");
} finally {
throw new MyError("BOOM1");
}
throw "(unreachable)";
}
it = asyncGeneratorForThrowInTryThrowInFinally();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
throw new MyError("EARLY2");
} finally {
throw new MyError("BOOM2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
throw new MyError("EARLY3");
} finally {
throw new MyError("BOOM3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("EARLY4");
} finally {
throw new MyError("BOOM4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("EARLY5");
} finally {
throw new MyError("BOOM5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Awaited Rejection in Try, ThrowStatement in Finally
async function* asyncGeneratorForAwaitedRejectInTryThrowInFinally() {
try {
await Rejecter("EARLY1");
} finally {
throw new MyError("BOOM1");
}
throw "(unreachable)";
}
it = asyncGeneratorForAwaitedRejectInTryThrowInFinally();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
await Rejecter("EARLY2");
} finally {
throw new MyError("BOOM2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
await Rejecter("EARLY3");
} finally {
throw new MyError("BOOM3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
await Rejecter("EARLY4");
} finally {
throw new MyError("BOOM4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
await Rejecter("EARLY5");
} finally {
throw new MyError("BOOM5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// ReturnStatement in Try, Awaited Rejection in Finally
async function* asyncGeneratorForReturnInTryAwaitedRejectionInFinally() {
try {
return "early1"
} finally {
await Rejecter("BOOM1");
}
throw "(unreachable)";
}
it = asyncGeneratorForReturnInTryAwaitedRejectionInFinally();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
return "early2";
} finally {
await Rejecter("BOOM2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
return "early3";
} finally {
await Rejecter("BOOM3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
return "early4";
} finally {
await Rejecter("BOOM4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
return "early5";
} finally {
await Rejecter("BOOM5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// ThrowStatement in Try, Awaited Rejection in Finally
async function* asyncGeneratorForThrowInTryAwaitedRejectionInFinally() {
try {
throw new MyError("EARLY1");
} finally {
await Rejecter("BOOM1");
}
throw "(unreachable)";
}
it = asyncGeneratorForThrowInTryAwaitedRejectionInFinally();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
throw new MyError("EARLY2");
} finally {
await Rejecter("BOOM2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
throw new MyError("EARLY3");
} finally {
await Rejecter("BOOM3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("EARLY4");
} finally {
await Rejecter("BOOM4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
throw new MyError("EARLY5");
} finally {
await Rejecter("BOOM5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Awaited Rejection in Try, Awaited Rejection in Finally
async function* asyncGeneratorForAwaitedRejectInTryAwaitedRejectionInFinally() {
try {
await Rejecter("EARLY1");
} finally {
await Rejecter("BOOM1");
}
throw "(unreachable)";
}
it = asyncGeneratorForAwaitedRejectInTryAwaitedRejectionInFinally();
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (async function*() {
try {
await Rejecter("EARLY2");
} finally {
await Rejecter("BOOM2");
}
throw "(unreachable)";
})();
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = ({
async* method() {
try {
await Rejecter("EARLY3");
} finally {
await Rejecter("BOOM3");
}
throw "(unreachable)";
}
}).method();
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
await Rejecter("EARLY4");
} finally {
await Rejecter("BOOM4");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
it = (AsyncGeneratorFunction(`
try {
await Rejecter("EARLY5");
} finally {
await Rejecter("BOOM5");
}
throw "(unreachable)";`))()
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
// ----------------------------------------------------------------------------
// Early errors during parameter initialization
async function* asyncGeneratorForParameterInitializationErrors(
[...a], b = c, d) {
AbortUnreachable();
}
assertThrows(() => asyncGeneratorForParameterInitializationErrors(null),
TypeError);
assertThrows(() => asyncGeneratorForParameterInitializationErrors([]),
ReferenceError);
let asyncGeneratorExprForParameterInitializationErrors =
async function*([...a], b = c, d) {
AbortUnreachable();
};
assertThrows(() => asyncGeneratorExprForParameterInitializationErrors(null),
TypeError);
assertThrows(() => asyncGeneratorExprForParameterInitializationErrors([]),
ReferenceError);
let asyncGeneratorMethodForParameterInitializationErrors = ({
async* method([...a], b = c, d) {
AbortUnreachable();
}
}).method;
assertThrows(() => asyncGeneratorMethodForParameterInitializationErrors(null),
TypeError);
assertThrows(() => asyncGeneratorMethodForParameterInitializationErrors([]),
ReferenceError);
let asyncGeneratorCallEvalForParameterInitializationErrors =
AsyncGeneratorFunction("[...a], b = c, d", `AbortUnreachable();`);
assertThrows(() => asyncGeneratorCallEvalForParameterInitializationErrors(null),
TypeError);
assertThrows(() => asyncGeneratorCallEvalForParameterInitializationErrors([]),
ReferenceError);
let asyncGeneratorNewEvalForParameterInitializationErrors =
new AsyncGeneratorFunction("[...a], b = c, d",
`AbortUnreachable();`);
assertThrows(() => asyncGeneratorNewEvalForParameterInitializationErrors(null),
TypeError);
assertThrows(() => asyncGeneratorNewEvalForParameterInitializationErrors([]),
ReferenceError);
// ----------------------------------------------------------------------------
// Invoke [AsyncGenerator].return() when generator is in state suspendedStart
async function* asyncGeneratorForReturnSuspendedStart() {
AbortUnreachable();
}
it = asyncGeneratorForReturnSuspendedStart();
assertEqualsAsync({ value: "ret1", done: true }, () => it.return("ret1"));
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = (async function*() {
AbortUnreachable();
})();
assertEqualsAsync({ value: "ret2", done: true }, () => it.return("ret2"));
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = ({
async* method() {
AbortUnreachable();
}
}).method();
assertEqualsAsync({ value: "ret3", done: true }, () => it.return("ret3"));
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = (AsyncGeneratorFunction(`AbortUnreachable();`))();
assertEqualsAsync({ value: "ret4", done: true }, () => it.return("ret4"));
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = (AsyncGeneratorFunction(`AbortUnreachable();`))();
assertEqualsAsync({ value: "ret5", done: true }, () => it.return("ret5"));
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
// ----------------------------------------------------------------------------
// Invoke [AsyncGenerator].throw() when generator is in state suspendedStart
async function* asyncGeneratorForThrowSuspendedStart() {
AbortUnreachable();
}
it = asyncGeneratorForReturnSuspendedStart();
assertThrowsAsync(() => it.throw(new MyError("throw1")), MyError, "throw1");
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = (async function*() {
AbortUnreachable();
})();
assertThrowsAsync(() => it.throw(new MyError("throw2")), MyError, "throw2");
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = ({
async* method() {
AbortUnreachable();
}
}).method();
assertThrowsAsync(() => it.throw(new MyError("throw3")), MyError, "throw3");
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = (AsyncGeneratorFunction(`AbortUnreachable()`))();
assertThrowsAsync(() => it.throw(new MyError("throw4")), MyError, "throw4");
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
it = (AsyncGeneratorFunction(`AbortUnreachable();`))();
assertThrowsAsync(() => it.throw(new MyError("throw5")), MyError, "throw5");
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
assertEqualsAsync({ value: "nores", done: true },
() => it.return("nores"));
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
// ----------------------------------------------------------------------------
// Simple yield*:
log = [];
async function* asyncGeneratorYieldStar1() {
yield* {
get [Symbol.asyncIterator]() {
log.push({ name: "get @@asyncIterator" });
return (...args) => {
log.push({ name: "call @@asyncIterator", args });
return this;
};
},
get [Symbol.iterator]() {
log.push({ name: "get @@iterator" });
return (...args) => {
log.push({ name: "call @@iterator", args });
return this;
}
},
get next() {
log.push({ name: "get next" });
return (...args) => {
log.push({ name: "call next", args });
return {
get then() {
log.push({ name: "get then" });
return null;
},
get value() {
log.push({ name: "get value" });
throw (exception = new MyError("AbruptValue!"));
},
get done() {
log.push({ name: "get done" });
return false;
}
};
}
},
get return() {
log.push({ name: "get return" });
return (...args) => {
log.push({ name: "call return", args });
return { value: args[0], done: true };
}
},
get throw() {
log.push({ name: "get throw" });
return (...args) => {
log.push({ name: "call throw", args });
throw args[0];
};
},
};
}
it = asyncGeneratorYieldStar1();
assertThrowsAsync(() => it.next(), MyError);
assertEquals([
{ name: "get @@asyncIterator" },
{ name: "call @@asyncIterator", args: [] },
{ name: "get next" },
{ name: "call next", args: [undefined] },
{ name: "get then" },
{ name: "get done" },
{ name: "get value" },
], log);
assertEqualsAsync({ value: undefined, done: true }, () => it.next());