OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // Flags: --harmony-async-iteration --allow-natives-syntax |
| 6 |
| 7 let testFailed = false; |
| 8 let testFailure; |
| 9 |
| 10 function assertThrowsAsync(run, errorType, message) { |
| 11 var actual; |
| 12 var hadValue = false; |
| 13 var hadError = false; |
| 14 var promise = run(); |
| 15 |
| 16 if (typeof promise !== "object" || typeof promise.then !== "function") { |
| 17 throw new MjsUnitAssertionError( |
| 18 "Expected " + run.toString() + |
| 19 " to return a Promise, but it returned " + PrettyPrint(promise)); |
| 20 } |
| 21 |
| 22 promise.then(function(value) { hadValue = true; actual = value; }, |
| 23 function(error) { hadError = true; actual = error; }); |
| 24 |
| 25 assertFalse(hadValue || hadError); |
| 26 |
| 27 %RunMicrotasks(); |
| 28 |
| 29 if (!hadError) { |
| 30 throw new MjsUnitAssertionError( |
| 31 "Expected " + run + "() to throw " + errorType.name + |
| 32 ", but did not throw."); |
| 33 } |
| 34 if (!(actual instanceof errorType)) |
| 35 throw new MjsUnitAssertionError( |
| 36 "Expected " + run + "() to throw " + errorType.name + |
| 37 ", but threw '" + actual + "'"); |
| 38 if (message !== void 0 && actual.message !== message) |
| 39 throw new MjsUnitAssertionError( |
| 40 "Expected " + run + "() to throw '" + message + "', but threw '" + |
| 41 actual.message + "'"); |
| 42 }; |
| 43 |
| 44 function resolveLater(value) { |
| 45 return new Promise(function(resolve) { |
| 46 Promise.resolve().then(function() { |
| 47 resolve(value); |
| 48 }); |
| 49 }); |
| 50 } |
| 51 |
| 52 function rejectLater(value) { |
| 53 return new Promise(function(resolve, reject) { |
| 54 Promise.resolve().then(function() { |
| 55 reject(value); |
| 56 }); |
| 57 }); |
| 58 } |
| 59 |
| 60 const kNext = 1; |
| 61 const kThrow = 2; |
| 62 const kReturn = 4; |
| 63 const kNextThrows = kNext | 8; |
| 64 const kReturnThrows = kReturn | 16; |
| 65 const kThrowNormal = kThrow | 32; |
| 66 const kNextUnchanged = kNext | 64; |
| 67 const kReturnUnchanged = kReturn | 128; |
| 68 const kThrowUnchanged = kThrow | 256; |
| 69 function sync(array, features, log) { |
| 70 // `log` is a required parameter |
| 71 if (log === void 0) %AbortJS("`log` is undefined"); |
| 72 |
| 73 let i = 0; |
| 74 let methods = { |
| 75 next(sent) { |
| 76 let done = i >= array.length; |
| 77 let value = array[i]; |
| 78 log.push({ method: "next", sent, value, done }); |
| 79 if ((features & kNextThrows) === kNextThrows) throw sent; |
| 80 if ((features & kNextUnchanged) === kNextUnchanged) return sent; |
| 81 i++; |
| 82 return { value, done }; |
| 83 }, |
| 84 throw(sent) { |
| 85 let done = i >= array.length; |
| 86 log.push({ method: "throw", sent, done }); |
| 87 if ((features & kThrowNormal) === kThrowNormal) |
| 88 return { value: sent, done }; |
| 89 if ((features & kThrowUnchanged) === kThrowUnchanged) return sent; |
| 90 throw sent; |
| 91 }, |
| 92 return(sent) { |
| 93 let done = true; |
| 94 log.push({ method: "return", sent, done }); |
| 95 if ((features & kReturnThrows) === kReturnThrows) throw sent; |
| 96 if ((features & kReturnUnchanged) === kReturnUnchanged) return sent; |
| 97 return { value: sent, done }; |
| 98 } |
| 99 }; |
| 100 return { |
| 101 [Symbol.iterator]() { return this; }, |
| 102 next: (features & kNext) ? methods.next : undefined, |
| 103 throw: (features & kThrow) ? methods.throw : undefined, |
| 104 return: (features & kReturn) ? methods.return : undefined |
| 105 }; |
| 106 } |
| 107 |
| 108 class MyError extends Error {}; |
| 109 |
| 110 (async function AsyncFromSyncWithGenerator() { |
| 111 function* gen() { |
| 112 yield "sync value"; |
| 113 try { |
| 114 yield new Promise(function(resolve) { |
| 115 resolve("async value"); |
| 116 }); |
| 117 } catch (error) { |
| 118 throw error; |
| 119 } |
| 120 assertUnreachable("generator is closed"); |
| 121 } |
| 122 let iter = %CreateAsyncFromSyncIterator(gen()); |
| 123 |
| 124 // [Async-from-Sync Iterator] wraps sync iterator values in a Promise |
| 125 let promise = iter.next(); |
| 126 assertInstanceof(promise, Promise); |
| 127 let iter_result = await promise; |
| 128 assertEquals({ value: "sync value", done: false }, iter_result); |
| 129 |
| 130 // [Async-from-Sync Iterator] will wait for resolution of Promise values |
| 131 promise = iter.next(); |
| 132 assertInstanceof(promise, Promise); |
| 133 iter_result = await promise; |
| 134 assertEquals({ value: "async value", done: false }, iter_result); |
| 135 |
| 136 // [Async-from-Sync Iterator].throw delegates to .throw() method of sync |
| 137 // iterator. |
| 138 promise = iter.throw(new MyError("Error#1")); |
| 139 assertInstanceof(promise, Promise); |
| 140 try { |
| 141 await promise; |
| 142 assertUnreachable("promise should be rejected"); |
| 143 } catch (e) { |
| 144 // If assertUnreachable failed, rethrow |
| 145 if (e instanceof MjsUnitAssertionError) throw e; |
| 146 assertInstanceof(e, MyError); |
| 147 assertEquals("Error#1", e.message); |
| 148 } |
| 149 |
| 150 // Generator is closed, subsequent calls to .next() will not resume. |
| 151 promise = iter.next("floof"); |
| 152 iter_result = await promise; |
| 153 assertEquals({ value: undefined, done: true }, iter_result); |
| 154 |
| 155 promise = iter.return("generator closed"); |
| 156 assertInstanceof(promise, Promise); |
| 157 iter_result = await promise; |
| 158 assertEquals({ value: "generator closed", done: true }, iter_result); |
| 159 |
| 160 // .next(), .return() and .throw() delegate to sync iterator methods, without |
| 161 // keeping track of the state of the generator. |
| 162 promise = iter.next("unused"); |
| 163 assertInstanceof(promise, Promise); |
| 164 iter_result = await promise; |
| 165 assertEquals({ value: undefined, done: true }, iter_result); |
| 166 |
| 167 promise = iter.throw(new MyError("Error#2")); |
| 168 assertInstanceof(promise, Promise); |
| 169 try { |
| 170 await promise; |
| 171 assertUnreachable("promise should be rejected"); |
| 172 } catch (e) { |
| 173 // If assertUnreachable failed, rethrow |
| 174 if (e instanceof MjsUnitAssertionError) throw e; |
| 175 assertInstanceof(e, MyError); |
| 176 assertEquals("Error#2", e.message); |
| 177 } |
| 178 |
| 179 promise = iter.return("return-after-completed"); |
| 180 assertInstanceof(promise, Promise); |
| 181 iter_result = await promise; |
| 182 assertEquals({ value: "return-after-completed", done: true }, iter_result); |
| 183 })().catch(function(error) { |
| 184 testFailed = true; |
| 185 testFailure = error; |
| 186 }); |
| 187 |
| 188 %RunMicrotasks(); |
| 189 if (testFailed) { |
| 190 throw testFailure; |
| 191 } |
| 192 |
| 193 |
| 194 (async function AsyncFromSyncOrderOfOperations() { |
| 195 let log = []; |
| 196 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], 0, log)); |
| 197 |
| 198 try { |
| 199 await iter.next(); |
| 200 assertUnreachable("Iterator.next() method is not optional"); |
| 201 } catch (e) { |
| 202 assertInstanceof(e, TypeError); |
| 203 assertEquals([], log); |
| 204 } |
| 205 |
| 206 log = []; |
| 207 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], kNext, log)); |
| 208 assertEquals({ value: "sync-value", done: false }, await iter.next("a")); |
| 209 assertEquals([ |
| 210 { |
| 211 method: "next", |
| 212 sent: "a", |
| 213 value: "sync-value", |
| 214 done: false |
| 215 } |
| 216 ], log); |
| 217 |
| 218 log = []; |
| 219 let asyncValue = resolveLater("async-value"); |
| 220 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log)); |
| 221 assertEquals({ value: "async-value", done: false }, await iter.next("b")); |
| 222 assertEquals([ |
| 223 { |
| 224 method: "next", |
| 225 sent: "b", |
| 226 value: asyncValue, |
| 227 done: false |
| 228 } |
| 229 ], log); |
| 230 |
| 231 // If [sync_iterator].next() produces a rejected Promise or an exception is |
| 232 // thrown, Promise is rejected with thrown/rejected value. |
| 233 log = []; |
| 234 asyncValue = rejectLater("Boo!"); |
| 235 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log)); |
| 236 try { |
| 237 await iter.next('c'); |
| 238 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw'); |
| 239 } catch (e) { |
| 240 assertEquals("Boo!", e); |
| 241 assertEquals([ |
| 242 { |
| 243 method: 'next', |
| 244 sent: 'c', |
| 245 value: asyncValue, |
| 246 done: false |
| 247 } |
| 248 ], log); |
| 249 } |
| 250 |
| 251 log = []; |
| 252 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextThrows, log)); |
| 253 try { |
| 254 await iter.next('Boo!'); |
| 255 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw'); |
| 256 } catch (e) { |
| 257 assertEquals("Boo!", e); |
| 258 assertEquals([ |
| 259 { |
| 260 method: 'next', |
| 261 sent: 'Boo!', |
| 262 value: 'sync-value', |
| 263 done: false |
| 264 } |
| 265 ], log); |
| 266 } |
| 267 |
| 268 |
| 269 // [Async-from-Sync Iterator].next() will be rejected with a TypeError if |
| 270 // Type([sync_iterator].next()) is not Object. |
| 271 log = []; |
| 272 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextUnchanged, |
| 273 log)); |
| 274 try { |
| 275 await iter.next('not-a-JSReceiver'); |
| 276 assertUnreachable('Expected `iter.next(\'not-a-JSReceiver\')` to ' + |
| 277 'throw, but did not throw') |
| 278 } catch (e) { |
| 279 assertEquals(e.constructor, TypeError); |
| 280 } |
| 281 |
| 282 assertEquals([ |
| 283 { |
| 284 method: 'next', |
| 285 sent: 'not-a-JSReceiver', |
| 286 value: 'sync-value', |
| 287 done: false |
| 288 } |
| 289 ], log); |
| 290 |
| 291 // If [sync_iterator] does not have a .return() method, return a Promise |
| 292 // resolved with the value `{ value: <<sent value>>, done: true }`. |
| 293 log = []; |
| 294 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], kNext, log)); |
| 295 assertEquals({ |
| 296 value: 'd', |
| 297 done: true |
| 298 }, await iter.return('d')); |
| 299 |
| 300 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 301 // whether [sync_iterator] is completed or not. |
| 302 assertEquals({ |
| 303 value: 'sync-return', |
| 304 done: false |
| 305 }, await iter.next('e')); |
| 306 |
| 307 assertEquals([ |
| 308 { |
| 309 method: 'next', |
| 310 sent: 'e', |
| 311 value: 'sync-return', |
| 312 done: false |
| 313 } |
| 314 ], log); |
| 315 |
| 316 // If [sync_iterator] does have a .return() method, return a Promise |
| 317 // fulfilled with the iterator result of [sync_iterator].return(). |
| 318 log = []; |
| 319 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], |
| 320 kNext|kReturn, log)); |
| 321 assertEquals({ |
| 322 value: 'f', |
| 323 done: true |
| 324 }, await iter.return('f')); |
| 325 |
| 326 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 327 // whether [sync_iterator] is completed or not. |
| 328 assertEquals({ |
| 329 value: 'sync-return', |
| 330 done: false |
| 331 }, await iter.next('g')); |
| 332 |
| 333 assertEquals([ |
| 334 { |
| 335 method: 'return', |
| 336 sent: 'f', |
| 337 done: true |
| 338 }, |
| 339 { |
| 340 method: 'next', |
| 341 sent: 'g', |
| 342 value: 'sync-return', |
| 343 done: false |
| 344 } |
| 345 ], log); |
| 346 |
| 347 // If [sync_iterator].return() produces a rejected Promise or an exception is |
| 348 // thrown, Promise is rejected with thrown/rejected value. |
| 349 log = []; |
| 350 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturnThrows, |
| 351 log)); |
| 352 try { |
| 353 await iter.return('Boo!!'); |
| 354 assertUnreachable('Expected `iter.return(\'Boo!!\')` to throw, but did ' + |
| 355 'not throw'); |
| 356 } catch (e) { |
| 357 assertEquals("Boo!!", e); |
| 358 } |
| 359 |
| 360 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 361 // whether [sync_iterator] is completed or not. |
| 362 assertEquals({ value: 'sync-value', done: false }, await iter.next('h')); |
| 363 assertEquals([ |
| 364 { |
| 365 method: 'return', |
| 366 sent: 'Boo!!', |
| 367 done: true |
| 368 }, |
| 369 { |
| 370 method: 'next', |
| 371 sent: 'h', |
| 372 value: 'sync-value', |
| 373 done: false |
| 374 } |
| 375 ], log); |
| 376 |
| 377 |
| 378 log = []; |
| 379 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturn, log)); |
| 380 |
| 381 let rejection = Promise.reject('Boo!!'); |
| 382 try { |
| 383 await iter.return(rejection); |
| 384 assertUnreachable('Expected `iter.return(Promise.reject(\'Boo!!\'))` to ' + |
| 385 'throw, but did not throw'); |
| 386 } catch (e) { |
| 387 assertEquals('Boo!!', e); |
| 388 } |
| 389 |
| 390 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 391 // whether [sync_iterator] is completed or not. |
| 392 assertEquals({ value: 'sync-value', done: false }, await iter.next('i')); |
| 393 assertEquals([ |
| 394 { |
| 395 method: 'return', |
| 396 sent: rejection, |
| 397 done: true |
| 398 }, |
| 399 { |
| 400 method: 'next', |
| 401 sent: 'i', |
| 402 value: 'sync-value', |
| 403 done: false |
| 404 } |
| 405 ], log); |
| 406 |
| 407 // [Async-from-Sync Iterator].return() will be rejected with a TypeError if |
| 408 // Type([sync_iterator].return()) is not Object. |
| 409 log = []; |
| 410 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], |
| 411 kNext|kReturnUnchanged, log)); |
| 412 try { |
| 413 await iter.return('not-a-JSReceiver'); |
| 414 assertUnreachable('Expected `iter.return(\'not-a-JSReceiver\')` to ' + |
| 415 'throw, but did not throw') |
| 416 } catch (e) { |
| 417 assertEquals(e.constructor, TypeError); |
| 418 } |
| 419 |
| 420 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 421 // whether [sync_iterator] is completed or not. |
| 422 assertEquals({ value: 'sync-value', done: false }, await iter.next('j')); |
| 423 assertEquals([ |
| 424 { |
| 425 method: 'return', |
| 426 sent: 'not-a-JSReceiver', |
| 427 done: true |
| 428 }, |
| 429 { |
| 430 method: 'next', |
| 431 sent: 'j', |
| 432 value: 'sync-value', |
| 433 done: false |
| 434 } |
| 435 ], log); |
| 436 |
| 437 // If [sync_iterator] does not have a .throw method, return a Promise rejected |
| 438 // with the sent value. |
| 439 log = []; |
| 440 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext, log)); |
| 441 try { |
| 442 await iter.throw('Boo!!'); |
| 443 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' + |
| 444 'throw'); |
| 445 } catch (e) { |
| 446 assertEquals('Boo!!', e); |
| 447 } |
| 448 |
| 449 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 450 // whether [sync_iterator] is completed or not. |
| 451 assertEquals({ value: 'sync-value', done: false }, await iter.next('k')); |
| 452 assertEquals([ |
| 453 { |
| 454 method: 'next', |
| 455 sent: 'k', |
| 456 value: 'sync-value', |
| 457 done: false |
| 458 } |
| 459 ], log); |
| 460 |
| 461 |
| 462 log = []; |
| 463 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrow, log)); |
| 464 try { |
| 465 await iter.throw('Boo!!'); |
| 466 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' + |
| 467 'throw'); |
| 468 } catch (e) { |
| 469 assertEquals('Boo!!', e); |
| 470 } |
| 471 |
| 472 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 473 // whether [sync_iterator] is completed or not. |
| 474 assertEquals({ value: 'sync-value', done: false }, await iter.next('l')); |
| 475 assertEquals([ |
| 476 { |
| 477 method: 'throw', |
| 478 sent: 'Boo!!', |
| 479 done: false |
| 480 }, |
| 481 { |
| 482 method: 'next', |
| 483 sent: 'l', |
| 484 value: 'sync-value', |
| 485 done: false |
| 486 } |
| 487 ], log); |
| 488 |
| 489 // If [sync_iterator].throw() returns a resolved Promise or a Completion |
| 490 // with [[Type]] "normal" or "return", return a resolved Promise |
| 491 log = []; |
| 492 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrowNormal, |
| 493 log)); |
| 494 assertEquals({ |
| 495 value: 'Boo!!', |
| 496 done: false |
| 497 }, await iter.throw('Boo!!')); |
| 498 |
| 499 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 500 // whether [sync_iterator] is completed or not. |
| 501 assertEquals({ value: 'sync-value', done: false }, await iter.next('m')); |
| 502 assertEquals([ |
| 503 { |
| 504 method: 'throw', |
| 505 sent: 'Boo!!', |
| 506 done: false |
| 507 }, |
| 508 { |
| 509 method: 'next', |
| 510 sent: 'm', |
| 511 value: 'sync-value', |
| 512 done: false |
| 513 } |
| 514 ], log); |
| 515 |
| 516 // [Async-from-Sync Iterator].throw() will be rejected with a TypeError if |
| 517 // Type([sync_iterator].throw()) is not Object. |
| 518 log = []; |
| 519 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], |
| 520 kNext|kThrowUnchanged, log)); |
| 521 try { |
| 522 await iter.throw('not-a-JSReceiver'); |
| 523 assertUnreachable('Expected `iter.throw(\'not-a-JSReceiver\')` to ' + |
| 524 'throw, but did not throw') |
| 525 } catch (e) { |
| 526 assertEquals(e.constructor, TypeError); |
| 527 } |
| 528 |
| 529 // [Async-from-Sync Iterator] merely delegates, and does not keep track of |
| 530 // whether [sync_iterator] is completed or not. |
| 531 assertEquals({ value: 'sync-value', done: false }, await iter.next('n')); |
| 532 assertEquals([ |
| 533 { |
| 534 method: 'throw', |
| 535 sent: 'not-a-JSReceiver', |
| 536 done: false |
| 537 }, |
| 538 { |
| 539 method: 'next', |
| 540 sent: 'n', |
| 541 value: 'sync-value', |
| 542 done: false |
| 543 } |
| 544 ], log); |
| 545 |
| 546 // Let nextValue be IteratorValue(nextResult). |
| 547 // IfAbruptRejectPromise(nextValue, promiseCapability).) |
| 548 iter = %CreateAsyncFromSyncIterator({ |
| 549 next() { return { get value() { throw "BadValue!" }, done: false }; } |
| 550 }); |
| 551 try { |
| 552 await iter.next(); |
| 553 assertUnreachable('Expected `iter.next()` to throw, but did not throw'); |
| 554 } catch (e) { |
| 555 assertEquals('BadValue!', e); |
| 556 } |
| 557 |
| 558 // Let nextDone be IteratorComplete(nextResult). |
| 559 // IfAbruptRejectPromise(nextDone, promiseCapability). |
| 560 iter = %CreateAsyncFromSyncIterator({ |
| 561 next() { return { value: undefined, get done() { throw "BadValue!" } }; } |
| 562 }); |
| 563 try { |
| 564 await iter.next(); |
| 565 assertUnreachable('Expected `iter.next()` to throw, but did not throw'); |
| 566 } catch (e) { |
| 567 assertEquals('BadValue!', e); |
| 568 } |
| 569 |
| 570 // IfAbruptRejectPromise(returnResult, promiseCapability). |
| 571 // Let returnValue be IteratorValue(returnResult). |
| 572 iter = %CreateAsyncFromSyncIterator({ |
| 573 return() { return { get value() { throw "BadValue!" }, done: false }; } |
| 574 }); |
| 575 try { |
| 576 await iter.return(); |
| 577 assertUnreachable('Expected `iter.return()` to throw, but did not throw'); |
| 578 } catch (e) { |
| 579 assertEquals('BadValue!', e); |
| 580 } |
| 581 |
| 582 // IfAbruptRejectPromise(returnValue, promiseCapability). |
| 583 // Let returnDone be IteratorComplete(returnResult). |
| 584 iter = %CreateAsyncFromSyncIterator({ |
| 585 return() { return { value: undefined, get done() { throw "BadValue!" } }; } |
| 586 }); |
| 587 try { |
| 588 await iter.return(); |
| 589 assertUnreachable('Expected `iter.return()` to throw, but did not throw'); |
| 590 } catch (e) { |
| 591 assertEquals('BadValue!', e); |
| 592 } |
| 593 |
| 594 // IfAbruptRejectPromise(throwResult, promiseCapability). |
| 595 // Let throwValue be IteratorValue(throwResult). |
| 596 iter = %CreateAsyncFromSyncIterator({ |
| 597 throw() { return { get value() { throw "BadValue!" }, done: false }; } |
| 598 }); |
| 599 try { |
| 600 await iter.throw(); |
| 601 assertUnreachable('Expected `iter.throw()` to throw, but did not throw'); |
| 602 } catch (e) { |
| 603 assertEquals('BadValue!', e); |
| 604 } |
| 605 |
| 606 // IfAbruptRejectPromise(throwValue, promiseCapability). |
| 607 // Let throwDone be IteratorComplete(throwResult). |
| 608 iter = %CreateAsyncFromSyncIterator({ |
| 609 throw() { return { value: undefined, get done() { throw "BadValue!" } }; } |
| 610 }); |
| 611 try { |
| 612 await iter.throw(); |
| 613 assertUnreachable('Expected `iter.throw()` to throw, but did not throw'); |
| 614 } catch (e) { |
| 615 assertEquals('BadValue!', e); |
| 616 } |
| 617 })().catch(function(error) { |
| 618 testFailed = true; |
| 619 testFailure = error; |
| 620 }); |
| 621 |
| 622 %RunMicrotasks(); |
| 623 if (testFailed) { |
| 624 throw testFailure; |
| 625 } |
| 626 |
| 627 (function ExtractedAsyncFromSyncIteratorMethods() { |
| 628 // Async-from-Sync iterator methods can be extracted via function.caller. |
| 629 // TODO(caitp): test extracted `throw` method using yield* in async generator. |
| 630 let extractor = [0, 1, 2, 3, 4,5,6,7,8,9]; |
| 631 let extractedNext; |
| 632 let extractedReturn; |
| 633 |
| 634 extractor[Symbol.iterator] = function() { |
| 635 let it = [][Symbol.iterator].call(extractor); |
| 636 let origNext = it.next, origThrow = it.throw, origReturn = it.return; |
| 637 function extractNext() { |
| 638 extractedNext = extractNext.caller; |
| 639 return origNext; |
| 640 } |
| 641 function extractReturn() { |
| 642 extractedReturn = extractReturn.caller; |
| 643 return origReturn; |
| 644 } |
| 645 Object.defineProperties(it, { |
| 646 "next": { get: extractNext, configurable: true }, |
| 647 "return": { get: extractReturn, configurable: true } |
| 648 }); |
| 649 return it; |
| 650 }; |
| 651 |
| 652 async function f() { |
| 653 let i; |
| 654 let it = extractor[Symbol.iterator](); |
| 655 for await (let x of it) break; |
| 656 for await (let x of it) return "x"; |
| 657 } |
| 658 |
| 659 // Cycle through `f` to extract iterator methods |
| 660 f().catch(function() { %AbortJS("No error should have occurred"); }); |
| 661 %RunMicrotasks(); |
| 662 |
| 663 assertEquals(typeof extractedNext, "function"); |
| 664 assertThrowsAsync(() => extractedNext.call(undefined), TypeError); |
| 665 assertThrowsAsync(() => extractedNext.call(1), TypeError); |
| 666 |
| 667 assertEquals(typeof extractedReturn, "function"); |
| 668 assertThrowsAsync(() => extractedReturn.call(undefined), TypeError); |
| 669 assertThrowsAsync(() => extractedReturn.call(1), TypeError); |
| 670 })(); |
OLD | NEW |