iterables-iteration-get-iterator-flattenable-abrupt-completion.js (4269B)
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 c. If desc is not undefined and desc.[[Enumerable]] is true, then 14 ... 15 iii. If value is not undefined, then 16 ... 17 2. Let iter be Completion(GetIteratorFlattenable(value, reject-strings)). 18 3. IfAbruptCloseIterators(iter, iters). 19 ... 20 21 GetIteratorFlattenable ( obj, primitiveHandling ) 22 1. If obj is not an Object, then 23 a. If primitiveHandling is reject-primitives, throw a TypeError exception. 24 b. Assert: primitiveHandling is iterate-string-primitives. 25 c. If obj is not a String, throw a TypeError exception. 26 2. Let method be ? GetMethod(obj, %Symbol.iterator%). 27 3. If method is undefined, then 28 a. Let iterator be obj. 29 4. Else, 30 a. Let iterator be ? Call(method, obj). 31 5. If iterator is not an Object, throw a TypeError exception. 32 6. Return ? GetIteratorDirect(iterator). 33 34 IteratorCloseAll ( iters, completion ) 35 1. For each element iter of iters, in reverse List order, do 36 a. Set completion to Completion(IteratorClose(iter, completion)). 37 2. Return ? completion. 38 39 IteratorClose ( iteratorRecord, completion ) 40 1. Assert: iteratorRecord.[[Iterator]] is an Object. 41 2. Let iterator be iteratorRecord.[[Iterator]]. 42 3. Let innerResult be Completion(GetMethod(iterator, "return")). 43 4. If innerResult is a normal completion, then 44 a. Let return be innerResult.[[Value]]. 45 b. If return is undefined, return ? completion. 46 c. Set innerResult to Completion(Call(return, iterator)). 47 5. If completion is a throw completion, return ? completion. 48 ... 49 includes: [compareArray.js] 50 features: [joint-iteration] 51 ---*/ 52 53 class ExpectedError extends Error {} 54 55 var badIterators = [ 56 // Throw TypeError in GetIteratorFlattenable because strings are rejected. 57 { 58 iterator: "bad iterator", 59 error: TypeError 60 }, 61 62 // Throw an error when GetIteratorFlattenable performs GetMethod. 63 { 64 iterator: { 65 get [Symbol.iterator]() { 66 throw new ExpectedError(); 67 } 68 }, 69 error: ExpectedError, 70 }, 71 72 // Throw an error when GetIteratorFlattenable performs Call. 73 { 74 iterator: { 75 [Symbol.iterator]() { 76 throw new ExpectedError(); 77 } 78 }, 79 error: ExpectedError, 80 }, 81 82 // Throw an error when GetIteratorFlattenable performs GetIteratorDirect. 83 { 84 iterator: { 85 get next() { 86 throw new ExpectedError(); 87 } 88 }, 89 error: ExpectedError, 90 }, 91 ]; 92 93 function makeIterables(badIterator) { 94 var log = []; 95 96 var first = { 97 next() { 98 log.push("unexpected call to next method"); 99 }, 100 return() { 101 // Called with the correct receiver and no arguments. 102 assert.sameValue(this, first); 103 assert.sameValue(arguments.length, 0); 104 105 // NB: Log after above asserts, because failures aren't propagated. 106 log.push("close first iterator"); 107 108 // IteratorClose ignores new exceptions when called with a Throw completion. 109 throw new Test262Error(); 110 }, 111 }; 112 113 var second = { 114 next() { 115 log.push("unexpected call to next method"); 116 }, 117 return() { 118 // Called with the correct receiver and no arguments. 119 assert.sameValue(this, second); 120 assert.sameValue(arguments.length, 0); 121 122 // NB: Log after above asserts, because failures aren't propagated. 123 log.push("close second iterator"); 124 125 // IteratorClose ignores new exceptions when called with a Throw completion. 126 throw new Test262Error(); 127 }, 128 }; 129 130 var iterables = {first, second, badIterator}; 131 132 return {log, iterables}; 133 } 134 135 for (var {iterator, error} of badIterators) { 136 var {log, iterables} = makeIterables(iterator); 137 138 assert.throws(error, function() { 139 Iterator.zipKeyed(iterables); 140 }); 141 142 // Ensure iterators are closed in the correct order. 143 assert.compareArray(log, [ 144 "close second iterator", 145 "close first iterator", 146 ]); 147 } 148 149 reportCompare(0, 0);