| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Flags: --allow-natives-syntax |
| |
| 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); |
| |
| %PerformMicrotaskCheckpoint(); |
| |
| 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); |
| |
| %PerformMicrotaskCheckpoint(); |
| |
| if (hadError) throw actual; |
| |
| assertTrue( |
| hadValue, "Expected '" + run.toString() + "' to produce a value"); |
| |
| assertEquals(expected, actual, msg); |
| }; |
| |
| class MyError extends Error {}; |
| function Thrower(msg) { throw new MyError(msg); } |
| function Rejecter(msg) { |
| return new Promise(function(resolve, reject) { |
| Promise.resolve().then(function() { |
| reject(new MyError(msg)); |
| }); |
| }); |
| } |
| function Resolver(msg) { |
| return new Promise(function(resolve, reject) { |
| Promise.resolve().then(function() { |
| resolve(msg); |
| }); |
| }); |
| } |
| |
| async function ForAwaitOfValues(it) { |
| let array = []; |
| for await (let x of it) array.push(x); |
| return array; |
| } |
| |
| let log = []; |
| function logIterResult(iter_result) { |
| log.push(iter_result); |
| } |
| function logError(error) { |
| log.push(error); |
| } |
| |
| function AbortUnreachable() { |
| %AbortJS("This code should not be reachable."); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Do not install `AsyncGeneratorFunction` constructor on global object |
| assertEquals(undefined, this.AsyncGeneratorFunction); |
| |
| // ---------------------------------------------------------------------------- |
| let AsyncGenerator = Object.getPrototypeOf(async function*() {}); |
| let AsyncGeneratorPrototype = AsyncGenerator.prototype; |
| |
| // %AsyncGenerator% and %AsyncGeneratorPrototype% are both ordinary objects |
| assertEquals("object", typeof AsyncGenerator); |
| assertEquals("object", typeof AsyncGeneratorPrototype); |
| |
| // %AsyncGenerator% <---> %AsyncGeneratorPrototype% circular reference |
| assertEquals(AsyncGenerator, AsyncGeneratorPrototype.constructor); |
| assertEquals(AsyncGeneratorPrototype, AsyncGenerator.prototype); |
| |
| let protoDesc = Object.getOwnPropertyDescriptor(AsyncGenerator, 'prototype'); |
| assertFalse(protoDesc.enumerable); |
| assertFalse(protoDesc.writable); |
| assertTrue(protoDesc.configurable); |
| |
| let ctorDesc = |
| Object.getOwnPropertyDescriptor(AsyncGeneratorPrototype, 'constructor'); |
| assertFalse(ctorDesc.enumerable); |
| assertFalse(ctorDesc.writable); |
| assertTrue(ctorDesc.configurable); |
| |
| // ---------------------------------------------------------------------------- |
| // The AsyncGeneratorFunction Constructor is the %AsyncGeneratorFunction% |
| // intrinsic object and is a subclass of Function. |
| // (proposal-async-iteration/#sec-asyncgeneratorfunction-constructor) |
| let AsyncGeneratorFunction = AsyncGenerator.constructor; |
| assertEquals(Object.getPrototypeOf(AsyncGeneratorFunction), Function); |
| assertEquals(Object.getPrototypeOf(AsyncGeneratorFunction.prototype), |
| Function.prototype); |
| assertTrue(async function*() {} instanceof Function); |
| |
| // ---------------------------------------------------------------------------- |
| // Let functionPrototype be the intrinsic object %AsyncGeneratorPrototype%. |
| async function* asyncGeneratorForProto() {} |
| assertEquals(AsyncGeneratorFunction.prototype, |
| Object.getPrototypeOf(asyncGeneratorForProto)); |
| assertEquals(AsyncGeneratorFunction.prototype, |
| Object.getPrototypeOf(async function*() {})); |
| assertEquals(AsyncGeneratorFunction.prototype, |
| Object.getPrototypeOf({ async* method() {} }.method)); |
| assertEquals(AsyncGeneratorFunction.prototype, |
| Object.getPrototypeOf(AsyncGeneratorFunction())); |
| assertEquals(AsyncGeneratorFunction.prototype, |
| Object.getPrototypeOf(new AsyncGeneratorFunction())); |
| |
| // ---------------------------------------------------------------------------- |
| // AsyncGeneratorFunctionCreate produces a function whose prototype property is |
| // derived from %AsyncGeneratorPrototype% |
| assertEquals(AsyncGeneratorFunction.prototype.prototype, |
| Object.getPrototypeOf(asyncGeneratorForProto.prototype)); |
| assertTrue(asyncGeneratorForProto.hasOwnProperty("prototype")); |
| assertEquals(AsyncGeneratorFunction.prototype.prototype, |
| Object.getPrototypeOf((async function*() {}).prototype)); |
| assertTrue((async function*() {}).hasOwnProperty("prototype")); |
| assertEquals(AsyncGeneratorFunction.prototype.prototype, |
| Object.getPrototypeOf(({ async* method() {} }).method.prototype)); |
| assertTrue(({ async* method() {} }).method.hasOwnProperty("prototype")); |
| assertEquals(AsyncGeneratorFunction.prototype.prototype, |
| Object.getPrototypeOf(AsyncGeneratorFunction().prototype)); |
| assertTrue(AsyncGeneratorFunction().hasOwnProperty("prototype")); |
| assertEquals(AsyncGeneratorFunction.prototype.prototype, |
| Object.getPrototypeOf(new AsyncGeneratorFunction().prototype)); |
| assertTrue(new AsyncGeneratorFunction().hasOwnProperty("prototype")); |
| |
| // ---------------------------------------------------------------------------- |
| // Basic Function.prototype.toString() |
| async function* asyncGeneratorForToString() {} |
| assertEquals("async function* asyncGeneratorForToString() {}", |
| asyncGeneratorForToString.toString()); |
| |
| assertEquals("async function*() {}", async function*() {}.toString()); |
| assertEquals("async function* namedAsyncGeneratorForToString() {}", |
| async function* namedAsyncGeneratorForToString() {}.toString()); |
| |
| assertEquals("async *method() { }", |
| ({ async *method() { } }).method.toString()); |
| assertEquals("async *method() { }", |
| (class { static async *method() { } }).method.toString()); |
| assertEquals("async *method() { }", |
| (new (class { async *method() { } })).method.toString()); |
| |
| assertEquals("async function* anonymous(\n) {\n\n}", |
| AsyncGeneratorFunction().toString()); |
| assertEquals("async function* anonymous(\n) {\n\n}", |
| (new AsyncGeneratorFunction()).toString()); |
| |
| // ---------------------------------------------------------------------------- |
| // 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| 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); |
| %PerformMicrotaskCheckpoint(); |
| assertEquals([ |
| { value: "step9", done: false }, |
| { value: "step10", done: true }, |
| { value: undefined, done: true }, |
| ], log); |
| |
| // ---------------------------------------------------------------------------- |
| // Top-level Yield ThrowStatement |
| |
| async function* asyncGeneratorForYieldThrow() { |
| yield await Thrower("OOPS1"); |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForYieldThrow(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { yield Thrower("OOPS2"); throw "(unreachable)"; })(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| yield Thrower("OOPS3"); |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = AsyncGeneratorFunction(` |
| yield Thrower("OOPS4"); |
| throw "(unreachable)"`)(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (new AsyncGeneratorFunction(` |
| yield Thrower("OOPS5"); |
| throw "(unreachable)"`))(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Top-level Yield Awaited Rejection |
| async function* asyncGeneratorForYieldAwaitedRejection() { |
| yield await Rejecter("OOPS1"); |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForYieldAwaitedRejection(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| yield await Rejecter("OOPS2"); |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| yield await Rejecter("OOPS3"); |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = AsyncGeneratorFunction(` |
| yield await Rejecter("OOPS4"); |
| throw "(unreachable)"`)(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (new AsyncGeneratorFunction(` |
| yield await Rejecter("OOPS5"); |
| throw "(unreachable)"`))(); |
| assertThrowsAsync(() => it.next(), MyError, "OOPS5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Top-level ThrowStatement |
| async function* asyncGeneratorForThrow() { |
| throw new MyError("BOOM1"); |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForThrow(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| throw new MyError("BOOM2"); |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| throw new MyError("BOOM3"); |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| throw new MyError("BOOM4"); |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| throw new MyError("BOOM5"); |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Top-level ThrowStatement after Await |
| async function* asyncGeneratorForThrowAfterAwait() { |
| await 1; |
| throw new MyError("BOOM6"); |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForThrowAfterAwait(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM6"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| await 1; |
| throw new MyError("BOOM7"); |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM7"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| await 1; |
| throw new MyError("BOOM8"); |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM8"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| await 1; |
| throw new MyError("BOOM9"); |
| throw "(unreachable)";`))(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM9"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (new AsyncGeneratorFunction(` |
| await 1; |
| throw new MyError("BOOM10"); |
| throw "(unreachable)";`))(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM10"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Top-level Awaited rejection |
| async function* asyncGeneratorForAwaitedRejection() { |
| await Rejecter("BOOM11"); |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForAwaitedRejection(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM11"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| await Rejecter("BOOM12"); |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM12"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| await Rejecter("BOOM13"); |
| throw "(unreachable)"; |
| } |
| }).method(); |
| |
| assertThrowsAsync(() => it.next(), MyError, "BOOM13"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| await Rejecter("BOOM14"); |
| throw "(unreachable)";`))(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM14"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (new AsyncGeneratorFunction(` |
| await Rejecter("BOOM15"); |
| throw "(unreachable)";`))(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM15"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Caught ThrowStatement |
| async function* asyncGeneratorForCaughtThrow() { |
| try { |
| throw new MyError("BOOM1"); |
| } catch (e) { |
| return "caught1"; |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForCaughtThrow(); |
| assertEqualsAsync({ value: "caught1", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| throw new MyError("BOOM2"); |
| } catch (e) { |
| return "caught2"; |
| } |
| throw "(unreachable)"; |
| })(); |
| assertEqualsAsync({ value: "caught2", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| throw new MyError("BOOM3"); |
| } catch (e) { |
| return "caught3"; |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertEqualsAsync({ value: "caught3", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("BOOM4"); |
| } catch (e) { |
| return "caught4"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "caught4", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("BOOM5"); |
| } catch (e) { |
| return "caught5"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "caught5", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Caught ThrowStatement and rethrow |
| async function* asyncGeneratorForCaughtRethrow() { |
| try { |
| throw new MyError("BOOM1"); |
| } catch (e) { |
| throw new MyError("RETHROW1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForCaughtRethrow(); |
| assertThrowsAsync(() => it.next(), MyError, "RETHROW1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| throw new MyError("BOOM2"); |
| } catch (e) { |
| throw new MyError("RETHROW2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "RETHROW2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| throw new MyError("BOOM3"); |
| } catch (e) { |
| throw new MyError("RETHROW3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "RETHROW3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("BOOM4"); |
| } catch (e) { |
| throw new MyError("RETHROW4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "RETHROW4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("BOOM5"); |
| } catch (e) { |
| throw new MyError("RETHROW5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "RETHROW5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // ReturnStatement in Try, ReturnStatement in Finally |
| async function* asyncGeneratorForReturnInTryReturnInFinally() { |
| try { |
| return "early1" |
| } finally { |
| return "later1"; |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForReturnInTryReturnInFinally(); |
| assertEqualsAsync({ value: "later1", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| return "early2"; |
| } finally { |
| return "later2"; |
| } |
| throw "(unreachable)"; |
| })(); |
| assertEqualsAsync({ value: "later2", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| return "early3"; |
| } finally { |
| return "later3"; |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertEqualsAsync({ value: "later3", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| return "early4"; |
| } finally { |
| return "later4"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "later4", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| return "early5"; |
| } finally { |
| return "later5"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "later5", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // ThrowStatement in Try, ReturnStatement in Finally |
| async function* asyncGeneratorForThrowInTryReturnInFinally() { |
| try { |
| throw new MyError("BOOM1"); |
| } finally { |
| return "later1"; |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForThrowInTryReturnInFinally(); |
| assertEqualsAsync({ value: "later1", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| throw new MyError("BOOM2"); |
| } finally { |
| return "later2"; |
| } |
| throw "(unreachable)"; |
| })(); |
| assertEqualsAsync({ value: "later2", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| throw new MyError("BOOM3"); |
| } finally { |
| return "later3"; |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertEqualsAsync({ value: "later3", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("BOOM4"); |
| } finally { |
| return "later4"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "later4", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("BOOM5"); |
| } finally { |
| return "later5"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "later5", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Awaited Rejection in Try, ReturnStatement in Finally |
| async function* asyncGeneratorForAwaitRejectionInTryReturnInFinally() { |
| try { |
| await Rejecter("BOOM1"); |
| } finally { |
| return "later1"; |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForThrowInTryReturnInFinally(); |
| assertEqualsAsync({ value: "later1", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| await Rejecter("BOOM2"); |
| } finally { |
| return "later2"; |
| } |
| throw "(unreachable)"; |
| })(); |
| assertEqualsAsync({ value: "later2", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| await Rejecter("BOOM3"); |
| } finally { |
| return "later3"; |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertEqualsAsync({ value: "later3", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| await Rejecter("BOOM4"); |
| } finally { |
| return "later4"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "later4", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| await Rejecter("BOOM5"); |
| } finally { |
| return "later5"; |
| } |
| throw "(unreachable)";`))() |
| assertEqualsAsync({ value: "later5", done: true }, () => it.next()); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // ReturnStatement in Try, ThrowStatement in Finally |
| async function* asyncGeneratorForReturnInTryThrowInFinally() { |
| try { |
| return "early1" |
| } finally { |
| throw new MyError("BOOM1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForReturnInTryThrowInFinally(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| return "early2"; |
| } finally { |
| throw new MyError("BOOM2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| return "early3"; |
| } finally { |
| throw new MyError("BOOM3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| return "early4"; |
| } finally { |
| throw new MyError("BOOM4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| return "early5"; |
| } finally { |
| throw new MyError("BOOM5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // ThrowStatement in Try, ThrowStatement in Finally |
| |
| async function* asyncGeneratorForThrowInTryThrowInFinally() { |
| try { |
| throw new MyError("EARLY1"); |
| } finally { |
| throw new MyError("BOOM1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForThrowInTryThrowInFinally(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| throw new MyError("EARLY2"); |
| } finally { |
| throw new MyError("BOOM2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| throw new MyError("EARLY3"); |
| } finally { |
| throw new MyError("BOOM3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("EARLY4"); |
| } finally { |
| throw new MyError("BOOM4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("EARLY5"); |
| } finally { |
| throw new MyError("BOOM5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Awaited Rejection in Try, ThrowStatement in Finally |
| |
| async function* asyncGeneratorForAwaitedRejectInTryThrowInFinally() { |
| try { |
| await Rejecter("EARLY1"); |
| } finally { |
| throw new MyError("BOOM1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForAwaitedRejectInTryThrowInFinally(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| await Rejecter("EARLY2"); |
| } finally { |
| throw new MyError("BOOM2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| await Rejecter("EARLY3"); |
| } finally { |
| throw new MyError("BOOM3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| await Rejecter("EARLY4"); |
| } finally { |
| throw new MyError("BOOM4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| await Rejecter("EARLY5"); |
| } finally { |
| throw new MyError("BOOM5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // ReturnStatement in Try, Awaited Rejection in Finally |
| async function* asyncGeneratorForReturnInTryAwaitedRejectionInFinally() { |
| try { |
| return "early1" |
| } finally { |
| await Rejecter("BOOM1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForReturnInTryAwaitedRejectionInFinally(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| return "early2"; |
| } finally { |
| await Rejecter("BOOM2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| return "early3"; |
| } finally { |
| await Rejecter("BOOM3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| return "early4"; |
| } finally { |
| await Rejecter("BOOM4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| return "early5"; |
| } finally { |
| await Rejecter("BOOM5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // ThrowStatement in Try, Awaited Rejection in Finally |
| |
| async function* asyncGeneratorForThrowInTryAwaitedRejectionInFinally() { |
| try { |
| throw new MyError("EARLY1"); |
| } finally { |
| await Rejecter("BOOM1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForThrowInTryAwaitedRejectionInFinally(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| throw new MyError("EARLY2"); |
| } finally { |
| await Rejecter("BOOM2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| throw new MyError("EARLY3"); |
| } finally { |
| await Rejecter("BOOM3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("EARLY4"); |
| } finally { |
| await Rejecter("BOOM4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| throw new MyError("EARLY5"); |
| } finally { |
| await Rejecter("BOOM5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Awaited Rejection in Try, Awaited Rejection in Finally |
| |
| async function* asyncGeneratorForAwaitedRejectInTryAwaitedRejectionInFinally() { |
| try { |
| await Rejecter("EARLY1"); |
| } finally { |
| await Rejecter("BOOM1"); |
| } |
| throw "(unreachable)"; |
| } |
| it = asyncGeneratorForAwaitedRejectInTryAwaitedRejectionInFinally(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (async function*() { |
| try { |
| await Rejecter("EARLY2"); |
| } finally { |
| await Rejecter("BOOM2"); |
| } |
| throw "(unreachable)"; |
| })(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = ({ |
| async* method() { |
| try { |
| await Rejecter("EARLY3"); |
| } finally { |
| await Rejecter("BOOM3"); |
| } |
| throw "(unreachable)"; |
| } |
| }).method(); |
| assertThrowsAsync(() => it.next(), MyError, "BOOM3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| await Rejecter("EARLY4"); |
| } finally { |
| await Rejecter("BOOM4"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| it = (AsyncGeneratorFunction(` |
| try { |
| await Rejecter("EARLY5"); |
| } finally { |
| await Rejecter("BOOM5"); |
| } |
| throw "(unreachable)";`))() |
| assertThrowsAsync(() => it.next(), MyError, "BOOM5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |
| |
| // ---------------------------------------------------------------------------- |
| // Early errors during parameter initialization |
| |
| async function* asyncGeneratorForParameterInitializationErrors( |
| [...a], b = c, d) { |
| AbortUnreachable(); |
| } |
| assertThrows(() => asyncGeneratorForParameterInitializationErrors(null), |
| TypeError); |
| assertThrows(() => asyncGeneratorForParameterInitializationErrors([]), |
| ReferenceError); |
| |
| let asyncGeneratorExprForParameterInitializationErrors = |
| async function*([...a], b = c, d) { |
| AbortUnreachable(); |
| }; |
| assertThrows(() => asyncGeneratorExprForParameterInitializationErrors(null), |
| TypeError); |
| assertThrows(() => asyncGeneratorExprForParameterInitializationErrors([]), |
| ReferenceError); |
| |
| let asyncGeneratorMethodForParameterInitializationErrors = ({ |
| async* method([...a], b = c, d) { |
| AbortUnreachable(); |
| } |
| }).method; |
| assertThrows(() => asyncGeneratorMethodForParameterInitializationErrors(null), |
| TypeError); |
| assertThrows(() => asyncGeneratorMethodForParameterInitializationErrors([]), |
| ReferenceError); |
| |
| let asyncGeneratorCallEvalForParameterInitializationErrors = |
| AsyncGeneratorFunction("[...a], b = c, d", `AbortUnreachable();`); |
| assertThrows(() => asyncGeneratorCallEvalForParameterInitializationErrors(null), |
| TypeError); |
| assertThrows(() => asyncGeneratorCallEvalForParameterInitializationErrors([]), |
| ReferenceError); |
| |
| let asyncGeneratorNewEvalForParameterInitializationErrors = |
| new AsyncGeneratorFunction("[...a], b = c, d", |
| `AbortUnreachable();`); |
| assertThrows(() => asyncGeneratorNewEvalForParameterInitializationErrors(null), |
| TypeError); |
| assertThrows(() => asyncGeneratorNewEvalForParameterInitializationErrors([]), |
| ReferenceError); |
| |
| // ---------------------------------------------------------------------------- |
| // Invoke [AsyncGenerator].return() when generator is in state suspendedStart |
| |
| async function* asyncGeneratorForReturnSuspendedStart() { |
| AbortUnreachable(); |
| } |
| it = asyncGeneratorForReturnSuspendedStart(); |
| assertEqualsAsync({ value: "ret1", done: true }, () => it.return("ret1")); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = (async function*() { |
| AbortUnreachable(); |
| })(); |
| assertEqualsAsync({ value: "ret2", done: true }, () => it.return("ret2")); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = ({ |
| async* method() { |
| AbortUnreachable(); |
| } |
| }).method(); |
| assertEqualsAsync({ value: "ret3", done: true }, () => it.return("ret3")); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = (AsyncGeneratorFunction(`AbortUnreachable();`))(); |
| assertEqualsAsync({ value: "ret4", done: true }, () => it.return("ret4")); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = (AsyncGeneratorFunction(`AbortUnreachable();`))(); |
| assertEqualsAsync({ value: "ret5", done: true }, () => it.return("ret5")); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| // ---------------------------------------------------------------------------- |
| // Invoke [AsyncGenerator].throw() when generator is in state suspendedStart |
| |
| async function* asyncGeneratorForThrowSuspendedStart() { |
| AbortUnreachable(); |
| } |
| it = asyncGeneratorForReturnSuspendedStart(); |
| assertThrowsAsync(() => it.throw(new MyError("throw1")), MyError, "throw1"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = (async function*() { |
| AbortUnreachable(); |
| })(); |
| assertThrowsAsync(() => it.throw(new MyError("throw2")), MyError, "throw2"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = ({ |
| async* method() { |
| AbortUnreachable(); |
| } |
| }).method(); |
| assertThrowsAsync(() => it.throw(new MyError("throw3")), MyError, "throw3"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = (AsyncGeneratorFunction(`AbortUnreachable()`))(); |
| assertThrowsAsync(() => it.throw(new MyError("throw4")), MyError, "throw4"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| it = (AsyncGeneratorFunction(`AbortUnreachable();`))(); |
| assertThrowsAsync(() => it.throw(new MyError("throw5")), MyError, "throw5"); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next("x")); |
| assertEqualsAsync({ value: "nores", done: true }, |
| () => it.return("nores")); |
| assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores"); |
| |
| // ---------------------------------------------------------------------------- |
| // Simple yield*: |
| |
| log = []; |
| async function* asyncGeneratorYieldStar1() { |
| yield* { |
| get [Symbol.asyncIterator]() { |
| log.push({ name: "get @@asyncIterator" }); |
| return (...args) => { |
| log.push({ name: "call @@asyncIterator", args }); |
| return this; |
| }; |
| }, |
| get [Symbol.iterator]() { |
| log.push({ name: "get @@iterator" }); |
| return (...args) => { |
| log.push({ name: "call @@iterator", args }); |
| return this; |
| } |
| }, |
| get next() { |
| log.push({ name: "get next" }); |
| return (...args) => { |
| log.push({ name: "call next", args }); |
| return { |
| get then() { |
| log.push({ name: "get then" }); |
| return null; |
| }, |
| get value() { |
| log.push({ name: "get value" }); |
| throw (exception = new MyError("AbruptValue!")); |
| }, |
| get done() { |
| log.push({ name: "get done" }); |
| return false; |
| } |
| }; |
| } |
| }, |
| get return() { |
| log.push({ name: "get return" }); |
| return (...args) => { |
| log.push({ name: "call return", args }); |
| return { value: args[0], done: true }; |
| } |
| }, |
| get throw() { |
| log.push({ name: "get throw" }); |
| return (...args) => { |
| log.push({ name: "call throw", args }); |
| throw args[0]; |
| }; |
| }, |
| }; |
| } |
| |
| it = asyncGeneratorYieldStar1(); |
| assertThrowsAsync(() => it.next(), MyError); |
| assertEquals([ |
| { name: "get @@asyncIterator" }, |
| { name: "call @@asyncIterator", args: [] }, |
| { name: "get next" }, |
| { name: "call next", args: [undefined] }, |
| { name: "get then" }, |
| { name: "get done" }, |
| { name: "get value" }, |
| ], log); |
| assertEqualsAsync({ value: undefined, done: true }, () => it.next()); |