| Index: test/mjsunit/harmony/async-from-sync-iterator.js
|
| diff --git a/test/mjsunit/harmony/async-from-sync-iterator.js b/test/mjsunit/harmony/async-from-sync-iterator.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9ca33c995d8baa33b6925373443e959d27ce56f6
|
| --- /dev/null
|
| +++ b/test/mjsunit/harmony/async-from-sync-iterator.js
|
| @@ -0,0 +1,670 @@
|
| +// 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: --harmony-async-iteration --allow-natives-syntax
|
| +
|
| +let testFailed = false;
|
| +let testFailure;
|
| +
|
| +function assertThrowsAsync(run, errorType, message) {
|
| + var actual;
|
| + var hadValue = false;
|
| + var hadError = false;
|
| + var promise = run();
|
| +
|
| + if (typeof promise !== "object" || typeof promise.then !== "function") {
|
| + throw new MjsUnitAssertionError(
|
| + "Expected " + run.toString() +
|
| + " to return a Promise, but it returned " + PrettyPrint(promise));
|
| + }
|
| +
|
| + promise.then(function(value) { hadValue = true; actual = value; },
|
| + function(error) { hadError = true; actual = error; });
|
| +
|
| + assertFalse(hadValue || hadError);
|
| +
|
| + %RunMicrotasks();
|
| +
|
| + if (!hadError) {
|
| + throw new MjsUnitAssertionError(
|
| + "Expected " + run + "() to throw " + errorType.name +
|
| + ", but did not throw.");
|
| + }
|
| + if (!(actual instanceof errorType))
|
| + throw new MjsUnitAssertionError(
|
| + "Expected " + run + "() to throw " + errorType.name +
|
| + ", but threw '" + actual + "'");
|
| + if (message !== void 0 && actual.message !== message)
|
| + throw new MjsUnitAssertionError(
|
| + "Expected " + run + "() to throw '" + message + "', but threw '" +
|
| + actual.message + "'");
|
| +};
|
| +
|
| +function resolveLater(value) {
|
| + return new Promise(function(resolve) {
|
| + Promise.resolve().then(function() {
|
| + resolve(value);
|
| + });
|
| + });
|
| +}
|
| +
|
| +function rejectLater(value) {
|
| + return new Promise(function(resolve, reject) {
|
| + Promise.resolve().then(function() {
|
| + reject(value);
|
| + });
|
| + });
|
| +}
|
| +
|
| +const kNext = 1;
|
| +const kThrow = 2;
|
| +const kReturn = 4;
|
| +const kNextThrows = kNext | 8;
|
| +const kReturnThrows = kReturn | 16;
|
| +const kThrowNormal = kThrow | 32;
|
| +const kNextUnchanged = kNext | 64;
|
| +const kReturnUnchanged = kReturn | 128;
|
| +const kThrowUnchanged = kThrow | 256;
|
| +function sync(array, features, log) {
|
| + // `log` is a required parameter
|
| + if (log === void 0) %AbortJS("`log` is undefined");
|
| +
|
| + let i = 0;
|
| + let methods = {
|
| + next(sent) {
|
| + let done = i >= array.length;
|
| + let value = array[i];
|
| + log.push({ method: "next", sent, value, done });
|
| + if ((features & kNextThrows) === kNextThrows) throw sent;
|
| + if ((features & kNextUnchanged) === kNextUnchanged) return sent;
|
| + i++;
|
| + return { value, done };
|
| + },
|
| + throw(sent) {
|
| + let done = i >= array.length;
|
| + log.push({ method: "throw", sent, done });
|
| + if ((features & kThrowNormal) === kThrowNormal)
|
| + return { value: sent, done };
|
| + if ((features & kThrowUnchanged) === kThrowUnchanged) return sent;
|
| + throw sent;
|
| + },
|
| + return(sent) {
|
| + let done = true;
|
| + log.push({ method: "return", sent, done });
|
| + if ((features & kReturnThrows) === kReturnThrows) throw sent;
|
| + if ((features & kReturnUnchanged) === kReturnUnchanged) return sent;
|
| + return { value: sent, done };
|
| + }
|
| + };
|
| + return {
|
| + [Symbol.iterator]() { return this; },
|
| + next: (features & kNext) ? methods.next : undefined,
|
| + throw: (features & kThrow) ? methods.throw : undefined,
|
| + return: (features & kReturn) ? methods.return : undefined
|
| + };
|
| +}
|
| +
|
| +class MyError extends Error {};
|
| +
|
| +(async function AsyncFromSyncWithGenerator() {
|
| + function* gen() {
|
| + yield "sync value";
|
| + try {
|
| + yield new Promise(function(resolve) {
|
| + resolve("async value");
|
| + });
|
| + } catch (error) {
|
| + throw error;
|
| + }
|
| + assertUnreachable("generator is closed");
|
| + }
|
| + let iter = %CreateAsyncFromSyncIterator(gen());
|
| +
|
| + // [Async-from-Sync Iterator] wraps sync iterator values in a Promise
|
| + let promise = iter.next();
|
| + assertInstanceof(promise, Promise);
|
| + let iter_result = await promise;
|
| + assertEquals({ value: "sync value", done: false }, iter_result);
|
| +
|
| + // [Async-from-Sync Iterator] will wait for resolution of Promise values
|
| + promise = iter.next();
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: "async value", done: false }, iter_result);
|
| +
|
| + // [Async-from-Sync Iterator].throw delegates to .throw() method of sync
|
| + // iterator.
|
| + promise = iter.throw(new MyError("Error#1"));
|
| + assertInstanceof(promise, Promise);
|
| + try {
|
| + await promise;
|
| + assertUnreachable("promise should be rejected");
|
| + } catch (e) {
|
| + // If assertUnreachable failed, rethrow
|
| + if (e instanceof MjsUnitAssertionError) throw e;
|
| + assertInstanceof(e, MyError);
|
| + assertEquals("Error#1", e.message);
|
| + }
|
| +
|
| + // Generator is closed, subsequent calls to .next() will not resume.
|
| + promise = iter.next("floof");
|
| + iter_result = await promise;
|
| + assertEquals({ value: undefined, done: true }, iter_result);
|
| +
|
| + promise = iter.return("generator closed");
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: "generator closed", done: true }, iter_result);
|
| +
|
| + // .next(), .return() and .throw() delegate to sync iterator methods, without
|
| + // keeping track of the state of the generator.
|
| + promise = iter.next("unused");
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: undefined, done: true }, iter_result);
|
| +
|
| + promise = iter.throw(new MyError("Error#2"));
|
| + assertInstanceof(promise, Promise);
|
| + try {
|
| + await promise;
|
| + assertUnreachable("promise should be rejected");
|
| + } catch (e) {
|
| + // If assertUnreachable failed, rethrow
|
| + if (e instanceof MjsUnitAssertionError) throw e;
|
| + assertInstanceof(e, MyError);
|
| + assertEquals("Error#2", e.message);
|
| + }
|
| +
|
| + promise = iter.return("return-after-completed");
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: "return-after-completed", done: true }, iter_result);
|
| +})().catch(function(error) {
|
| + testFailed = true;
|
| + testFailure = error;
|
| +});
|
| +
|
| +%RunMicrotasks();
|
| +if (testFailed) {
|
| + throw testFailure;
|
| +}
|
| +
|
| +
|
| +(async function AsyncFromSyncOrderOfOperations() {
|
| + let log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], 0, log));
|
| +
|
| + try {
|
| + await iter.next();
|
| + assertUnreachable("Iterator.next() method is not optional");
|
| + } catch (e) {
|
| + assertInstanceof(e, TypeError);
|
| + assertEquals([], log);
|
| + }
|
| +
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], kNext, log));
|
| + assertEquals({ value: "sync-value", done: false }, await iter.next("a"));
|
| + assertEquals([
|
| + {
|
| + method: "next",
|
| + sent: "a",
|
| + value: "sync-value",
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + log = [];
|
| + let asyncValue = resolveLater("async-value");
|
| + iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
|
| + assertEquals({ value: "async-value", done: false }, await iter.next("b"));
|
| + assertEquals([
|
| + {
|
| + method: "next",
|
| + sent: "b",
|
| + value: asyncValue,
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].next() produces a rejected Promise or an exception is
|
| + // thrown, Promise is rejected with thrown/rejected value.
|
| + log = [];
|
| + asyncValue = rejectLater("Boo!");
|
| + iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
|
| + try {
|
| + await iter.next('c');
|
| + assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals("Boo!", e);
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'c',
|
| + value: asyncValue,
|
| + done: false
|
| + }
|
| + ], log);
|
| + }
|
| +
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextThrows, log));
|
| + try {
|
| + await iter.next('Boo!');
|
| + assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals("Boo!", e);
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'Boo!',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| + }
|
| +
|
| +
|
| + // [Async-from-Sync Iterator].next() will be rejected with a TypeError if
|
| + // Type([sync_iterator].next()) is not Object.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextUnchanged,
|
| + log));
|
| + try {
|
| + await iter.next('not-a-JSReceiver');
|
| + assertUnreachable('Expected `iter.next(\'not-a-JSReceiver\')` to ' +
|
| + 'throw, but did not throw')
|
| + } catch (e) {
|
| + assertEquals(e.constructor, TypeError);
|
| + }
|
| +
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'not-a-JSReceiver',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator] does not have a .return() method, return a Promise
|
| + // resolved with the value `{ value: <<sent value>>, done: true }`.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], kNext, log));
|
| + assertEquals({
|
| + value: 'd',
|
| + done: true
|
| + }, await iter.return('d'));
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({
|
| + value: 'sync-return',
|
| + done: false
|
| + }, await iter.next('e'));
|
| +
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'e',
|
| + value: 'sync-return',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator] does have a .return() method, return a Promise
|
| + // fulfilled with the iterator result of [sync_iterator].return().
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-return'],
|
| + kNext|kReturn, log));
|
| + assertEquals({
|
| + value: 'f',
|
| + done: true
|
| + }, await iter.return('f'));
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({
|
| + value: 'sync-return',
|
| + done: false
|
| + }, await iter.next('g'));
|
| +
|
| + assertEquals([
|
| + {
|
| + method: 'return',
|
| + sent: 'f',
|
| + done: true
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'g',
|
| + value: 'sync-return',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].return() produces a rejected Promise or an exception is
|
| + // thrown, Promise is rejected with thrown/rejected value.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturnThrows,
|
| + log));
|
| + try {
|
| + await iter.return('Boo!!');
|
| + assertUnreachable('Expected `iter.return(\'Boo!!\')` to throw, but did ' +
|
| + 'not throw');
|
| + } catch (e) {
|
| + assertEquals("Boo!!", e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('h'));
|
| + assertEquals([
|
| + {
|
| + method: 'return',
|
| + sent: 'Boo!!',
|
| + done: true
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'h',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| +
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturn, log));
|
| +
|
| + let rejection = Promise.reject('Boo!!');
|
| + try {
|
| + await iter.return(rejection);
|
| + assertUnreachable('Expected `iter.return(Promise.reject(\'Boo!!\'))` to ' +
|
| + 'throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('Boo!!', e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('i'));
|
| + assertEquals([
|
| + {
|
| + method: 'return',
|
| + sent: rejection,
|
| + done: true
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'i',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // [Async-from-Sync Iterator].return() will be rejected with a TypeError if
|
| + // Type([sync_iterator].return()) is not Object.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'],
|
| + kNext|kReturnUnchanged, log));
|
| + try {
|
| + await iter.return('not-a-JSReceiver');
|
| + assertUnreachable('Expected `iter.return(\'not-a-JSReceiver\')` to ' +
|
| + 'throw, but did not throw')
|
| + } catch (e) {
|
| + assertEquals(e.constructor, TypeError);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('j'));
|
| + assertEquals([
|
| + {
|
| + method: 'return',
|
| + sent: 'not-a-JSReceiver',
|
| + done: true
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'j',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator] does not have a .throw method, return a Promise rejected
|
| + // with the sent value.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext, log));
|
| + try {
|
| + await iter.throw('Boo!!');
|
| + assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
|
| + 'throw');
|
| + } catch (e) {
|
| + assertEquals('Boo!!', e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('k'));
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'k',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| +
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrow, log));
|
| + try {
|
| + await iter.throw('Boo!!');
|
| + assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
|
| + 'throw');
|
| + } catch (e) {
|
| + assertEquals('Boo!!', e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('l'));
|
| + assertEquals([
|
| + {
|
| + method: 'throw',
|
| + sent: 'Boo!!',
|
| + done: false
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'l',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].throw() returns a resolved Promise or a Completion
|
| + // with [[Type]] "normal" or "return", return a resolved Promise
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrowNormal,
|
| + log));
|
| + assertEquals({
|
| + value: 'Boo!!',
|
| + done: false
|
| + }, await iter.throw('Boo!!'));
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('m'));
|
| + assertEquals([
|
| + {
|
| + method: 'throw',
|
| + sent: 'Boo!!',
|
| + done: false
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'm',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // [Async-from-Sync Iterator].throw() will be rejected with a TypeError if
|
| + // Type([sync_iterator].throw()) is not Object.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'],
|
| + kNext|kThrowUnchanged, log));
|
| + try {
|
| + await iter.throw('not-a-JSReceiver');
|
| + assertUnreachable('Expected `iter.throw(\'not-a-JSReceiver\')` to ' +
|
| + 'throw, but did not throw')
|
| + } catch (e) {
|
| + assertEquals(e.constructor, TypeError);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('n'));
|
| + assertEquals([
|
| + {
|
| + method: 'throw',
|
| + sent: 'not-a-JSReceiver',
|
| + done: false
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'n',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // Let nextValue be IteratorValue(nextResult).
|
| + // IfAbruptRejectPromise(nextValue, promiseCapability).)
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + next() { return { get value() { throw "BadValue!" }, done: false }; }
|
| + });
|
| + try {
|
| + await iter.next();
|
| + assertUnreachable('Expected `iter.next()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // Let nextDone be IteratorComplete(nextResult).
|
| + // IfAbruptRejectPromise(nextDone, promiseCapability).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + next() { return { value: undefined, get done() { throw "BadValue!" } }; }
|
| + });
|
| + try {
|
| + await iter.next();
|
| + assertUnreachable('Expected `iter.next()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(returnResult, promiseCapability).
|
| + // Let returnValue be IteratorValue(returnResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + return() { return { get value() { throw "BadValue!" }, done: false }; }
|
| + });
|
| + try {
|
| + await iter.return();
|
| + assertUnreachable('Expected `iter.return()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(returnValue, promiseCapability).
|
| + // Let returnDone be IteratorComplete(returnResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + return() { return { value: undefined, get done() { throw "BadValue!" } }; }
|
| + });
|
| + try {
|
| + await iter.return();
|
| + assertUnreachable('Expected `iter.return()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(throwResult, promiseCapability).
|
| + // Let throwValue be IteratorValue(throwResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + throw() { return { get value() { throw "BadValue!" }, done: false }; }
|
| + });
|
| + try {
|
| + await iter.throw();
|
| + assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(throwValue, promiseCapability).
|
| + // Let throwDone be IteratorComplete(throwResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + throw() { return { value: undefined, get done() { throw "BadValue!" } }; }
|
| + });
|
| + try {
|
| + await iter.throw();
|
| + assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +})().catch(function(error) {
|
| + testFailed = true;
|
| + testFailure = error;
|
| +});
|
| +
|
| +%RunMicrotasks();
|
| +if (testFailed) {
|
| + throw testFailure;
|
| +}
|
| +
|
| +(function ExtractedAsyncFromSyncIteratorMethods() {
|
| + // Async-from-Sync iterator methods can be extracted via function.caller.
|
| + // TODO(caitp): test extracted `throw` method using yield* in async generator.
|
| + let extractor = [0, 1, 2, 3, 4,5,6,7,8,9];
|
| + let extractedNext;
|
| + let extractedReturn;
|
| +
|
| + extractor[Symbol.iterator] = function() {
|
| + let it = [][Symbol.iterator].call(extractor);
|
| + let origNext = it.next, origThrow = it.throw, origReturn = it.return;
|
| + function extractNext() {
|
| + extractedNext = extractNext.caller;
|
| + return origNext;
|
| + }
|
| + function extractReturn() {
|
| + extractedReturn = extractReturn.caller;
|
| + return origReturn;
|
| + }
|
| + Object.defineProperties(it, {
|
| + "next": { get: extractNext, configurable: true },
|
| + "return": { get: extractReturn, configurable: true }
|
| + });
|
| + return it;
|
| + };
|
| +
|
| + async function f() {
|
| + let i;
|
| + let it = extractor[Symbol.iterator]();
|
| + for await (let x of it) break;
|
| + for await (let x of it) return "x";
|
| + }
|
| +
|
| + // Cycle through `f` to extract iterator methods
|
| + f().catch(function() { %AbortJS("No error should have occurred"); });
|
| + %RunMicrotasks();
|
| +
|
| + assertEquals(typeof extractedNext, "function");
|
| + assertThrowsAsync(() => extractedNext.call(undefined), TypeError);
|
| + assertThrowsAsync(() => extractedNext.call(1), TypeError);
|
| +
|
| + assertEquals(typeof extractedReturn, "function");
|
| + assertThrowsAsync(() => extractedReturn.call(undefined), TypeError);
|
| + assertThrowsAsync(() => extractedReturn.call(1), TypeError);
|
| +})();
|
|
|