[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.
|
|
|
|
|
|
2018-01-12 19:33:13 +00:00
|
|
|
|
// 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);
|
|
|
|
|
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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
|
|
|
|
|
|
|
|
|
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);
|
2018-06-26 12:11:10 +00:00
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
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)
|
2018-06-26 12:11:10 +00:00
|
|
|
|
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"));
|
|
|
|
|
|
2017-03-30 14:34:34 +00:00
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Basic Function.prototype.toString()
|
|
|
|
|
async function* asyncGeneratorForToString() {}
|
|
|
|
|
assertEquals("async function* asyncGeneratorForToString() {}",
|
|
|
|
|
asyncGeneratorForToString.toString());
|
|
|
|
|
|
2017-12-19 19:14:44 +00:00
|
|
|
|
assertEquals("async function*() {}", async function*() {}.toString());
|
2017-03-30 14:34:34 +00:00
|
|
|
|
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());
|
|
|
|
|
|
2017-12-19 19:14:44 +00:00
|
|
|
|
assertEquals("async function* anonymous(\n) {\n\n}",
|
2017-03-30 14:34:34 +00:00
|
|
|
|
AsyncGeneratorFunction().toString());
|
2017-12-19 19:14:44 +00:00
|
|
|
|
assertEquals("async function* anonymous(\n) {\n\n}",
|
2017-03-30 14:34:34 +00:00
|
|
|
|
(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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
"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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
"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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
"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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
"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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
"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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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);
|
2018-12-04 06:12:49 +00:00
|
|
|
|
%PerformMicrotaskCheckpoint();
|
[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([
|
|
|
|
|
{ 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");
|
2017-04-13 12:57:06 +00:00
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// 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());
|