iterables-iteration-get-abrupt-completion.js (3568B)
1 // Copyright (C) 2025 André Bargull. All rights reserved. 2 // This code is governed by the BSD license found in the LICENSE file. 3 4 /*--- 5 esid: sec-iterator.zipkeyed 6 description: > 7 Handle abrupt completions during iterables iteration. 8 info: | 9 Iterator.zipKeyed ( iterables [ , options ] ) 10 ... 11 12. For each element key of allKeys, do 12 ... 13 3. If desc is not undefined and desc.[[Enumerable]] is true, then 14 i. Let value be Completion(Get(iterables, key)). 15 ii. IfAbruptCloseIterators(value, iters). 16 ... 17 18 IfAbruptCloseIterators ( value, iteratorRecords ) 19 1. Assert: value is a Completion Record. 20 2. If value is an abrupt completion, return ? IteratorCloseAll(iteratorRecords, value). 21 3. Else, set value to value.[[Value]]. 22 23 IteratorCloseAll ( iters, completion ) 24 1. For each element iter of iters, in reverse List order, do 25 a. Set completion to Completion(IteratorClose(iter, completion)). 26 2. Return ? completion. 27 28 IteratorClose ( iteratorRecord, completion ) 29 1. Assert: iteratorRecord.[[Iterator]] is an Object. 30 2. Let iterator be iteratorRecord.[[Iterator]]. 31 3. Let innerResult be Completion(GetMethod(iterator, "return")). 32 4. If innerResult is a normal completion, then 33 a. Let return be innerResult.[[Value]]. 34 b. If return is undefined, return ? completion. 35 c. Set innerResult to Completion(Call(return, iterator)). 36 5. If completion is a throw completion, return ? completion. 37 ... 38 includes: [compareArray.js] 39 features: [joint-iteration] 40 ---*/ 41 42 class ExpectedError extends Error {} 43 44 var log = []; 45 46 var first = { 47 next() { 48 log.push("unexpected call to next method"); 49 }, 50 return() { 51 // Called with the correct receiver and no arguments. 52 assert.sameValue(this, first); 53 assert.sameValue(arguments.length, 0); 54 55 // NB: Log after above asserts, because failures aren't propagated. 56 log.push("close first iterator"); 57 58 // IteratorClose ignores new exceptions when called with a Throw completion. 59 throw new Test262Error(); 60 }, 61 }; 62 63 var second = { 64 next() { 65 log.push("unexpected call to next method"); 66 }, 67 return() { 68 // Called with the correct receiver and no arguments. 69 assert.sameValue(this, second); 70 assert.sameValue(arguments.length, 0); 71 72 // NB: Log after above asserts, because failures aren't propagated. 73 log.push("close second iterator"); 74 75 // IteratorClose ignores new exceptions when called with a Throw completion. 76 throw new Test262Error(); 77 }, 78 }; 79 80 var symbol = { 81 next() { 82 log.push("unexpected call to next method"); 83 }, 84 return() { 85 log.push("unexpected call to return method"); 86 }, 87 }; 88 89 var arrayIndex = { 90 next() { 91 log.push("unexpected call to next method"); 92 }, 93 return() { 94 // Called with the correct receiver and no arguments. 95 assert.sameValue(this, arrayIndex); 96 assert.sameValue(arguments.length, 0); 97 98 // NB: Log after above asserts, because failures aren't propagated. 99 log.push("close array-indexed iterator"); 100 101 // IteratorClose ignores new exceptions when called with a Throw completion. 102 throw new Test262Error(); 103 }, 104 }; 105 106 var iterables = { 107 [Symbol()]: symbol, 108 first, 109 second, 110 get third() { 111 throw new ExpectedError(); 112 }, 113 5: arrayIndex, 114 }; 115 116 assert.throws(ExpectedError, function() { 117 Iterator.zipKeyed(iterables); 118 }); 119 120 // Ensure iterators are closed in the correct order. 121 assert.compareArray(log, [ 122 "close second iterator", 123 "close first iterator", 124 "close array-indexed iterator", 125 ]); 126 127 reportCompare(0, 0);