| // 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 | 
 |  | 
 | 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); | 
 |  | 
 |   %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 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; | 
 | }); | 
 |  | 
 | %PerformMicrotaskCheckpoint(); | 
 | 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; | 
 | }); | 
 |  | 
 | %PerformMicrotaskCheckpoint(); | 
 | if (testFailed) { | 
 |   throw testFailure; | 
 | } | 
 |  | 
 | (function ExtractedAsyncFromSyncIteratorMethods() { | 
 |   // TODO(ishell, caitp): Rewrite the test without using function.caller. | 
 |   // According to ES#sec-built-in-function-objects all built-in functions | 
 |   // must be strict. And ES#sec-forbidden-extensions states that the value of | 
 |   // a function.caller must not be a strict function. | 
 |   return; | 
 |   // 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"); }); | 
 |   %PerformMicrotaskCheckpoint(); | 
 |  | 
 |   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); | 
 | })(); | 
 |  | 
 | (function AsyncFromSyncIteratorOrdering() { | 
 |   let i = 0; | 
 |   let log = []; | 
 |   function r(value, done) { | 
 |     let number = (++i); | 
 |     return { | 
 |       get value() { | 
 |         log.push("get iterResult #" + number + ".value"); | 
 |         return { | 
 |           get then() { | 
 |             log.push("get nextValue#" + number + ".then"); | 
 |             return (r) => { | 
 |               log.push("call nextValue#" + number + ".then"); | 
 |               r(value); | 
 |             } | 
 |           } | 
 |         }; | 
 |       }, | 
 |       get done() { | 
 |         log.push("get iterResult #" + number + ".done"); | 
 |         return done; | 
 |       } | 
 |     }; | 
 |   } | 
 |   var results = [r("value1", false), r("value2", false), r("value3", true), | 
 |                  r("value4", false)]; | 
 |  | 
 |   var iter = { | 
 |     get [Symbol.asyncIterator]() { | 
 |       log.push("get syncIterable[@@asyncIterator]"); | 
 |       return null; | 
 |     }, | 
 |  | 
 |     get [Symbol.iterator]() { | 
 |       log.push("get syncIterable[@@iterator]"); | 
 |       return (...args) => { | 
 |         log.push("call syncIterable[@@iterator](" + args.join(", ") + ")"); | 
 |         return this; | 
 |       } | 
 |     }, | 
 |     next_: 0, | 
 |     get next() { | 
 |       log.push("get syncIterable.next"); | 
 |       return (...args) => { | 
 |         let i = this.next_++; | 
 |         log.push("call syncIterable.next(" + args.join(", ") + ")"); | 
 |         return results[i]; | 
 |       } | 
 |     } | 
 |   }; | 
 |  | 
 |   async function iterate(iterable) { | 
 |     log.push("before"); | 
 |     for await (let x of iterable) { | 
 |       log.push("got value " + x); | 
 |     } | 
 |     log.push("after"); | 
 |  | 
 |     return log; | 
 |   } | 
 |  | 
 |   iterate(iter).then(log => { | 
 |     assertEquals([ | 
 |       "before", | 
 |       "get syncIterable[@@asyncIterator]", | 
 |       "get syncIterable[@@iterator]", | 
 |       "call syncIterable[@@iterator]()", | 
 |       "get syncIterable.next", | 
 |       "call syncIterable.next()", | 
 |       "get iterResult #1.done", | 
 |       "get iterResult #1.value", | 
 |       "get nextValue#1.then", | 
 |       "call nextValue#1.then", | 
 |       "got value value1", | 
 |       "call syncIterable.next()", | 
 |       "get iterResult #2.done", | 
 |       "get iterResult #2.value", | 
 |       "get nextValue#2.then", | 
 |       "call nextValue#2.then", | 
 |       "got value value2", | 
 |       "call syncIterable.next()", | 
 |       "get iterResult #3.done", | 
 |       "get iterResult #3.value", | 
 |       "get nextValue#3.then", | 
 |       "call nextValue#3.then", | 
 |       "after" | 
 |     ], log) | 
 |   }).catch(x => %AbortJS(String(x))); | 
 | })(); |