padding-iteration-iterator-close-abrupt-completion.js (3415B)
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.zip 6 description: > 7 Abrupt completion for IteratorClose in "padding" option iteration. 8 info: | 9 Iterator.zip ( iterables [ , options ] ) 10 ... 11 14. If mode is "longest", then 12 ... 13 b. Else, 14 i. Let paddingIter be Completion(GetIterator(paddingOption, sync)). 15 ... 16 v. If usingIterator is true, then 17 1. Let completion be Completion(IteratorClose(paddingIter, NormalCompletion(unused))). 18 2. IfAbruptCloseIterators(completion, iters). 19 ... 20 21 IfAbruptCloseIterators ( value, iteratorRecords ) 22 1. Assert: value is a Completion Record. 23 2. If value is an abrupt completion, return ? IteratorCloseAll(iteratorRecords, value). 24 3. Else, set value to value.[[Value]]. 25 26 IteratorCloseAll ( iters, completion ) 27 1. For each element iter of iters, in reverse List order, do 28 a. Set completion to Completion(IteratorClose(iter, completion)). 29 2. Return ? completion. 30 31 IteratorClose ( iteratorRecord, completion ) 32 1. Assert: iteratorRecord.[[Iterator]] is an Object. 33 2. Let iterator be iteratorRecord.[[Iterator]]. 34 3. Let innerResult be Completion(GetMethod(iterator, "return")). 35 4. If innerResult is a normal completion, then 36 a. Let return be innerResult.[[Value]]. 37 b. If return is undefined, return ? completion. 38 c. Set innerResult to Completion(Call(return, iterator)). 39 5. If completion is a throw completion, return ? completion. 40 ... 41 includes: [compareArray.js] 42 features: [joint-iteration] 43 ---*/ 44 45 var log = []; 46 47 var first = { 48 next() { 49 log.push("unexpected call to next method"); 50 }, 51 return() { 52 // Called with the correct receiver and no arguments. 53 assert.sameValue(this, first); 54 assert.sameValue(arguments.length, 0); 55 56 // NB: Log after above asserts, because failures aren't propagated. 57 log.push("first return"); 58 59 // This exception is ignored. 60 throw new Test262Error(); 61 } 62 }; 63 64 var second = { 65 next() { 66 log.push("unexpected call to next method"); 67 }, 68 return() { 69 // Called with the correct receiver and no arguments. 70 assert.sameValue(this, second); 71 assert.sameValue(arguments.length, 0); 72 73 // NB: Log after above asserts, because failures aren't propagated. 74 log.push("second return"); 75 76 // This exception is ignored. 77 throw new Test262Error(); 78 } 79 }; 80 81 var third = { 82 next() { 83 log.push("unexpected call to next method"); 84 }, 85 get return() { 86 // Called with the correct receiver and no arguments. 87 assert.sameValue(this, third); 88 assert.sameValue(arguments.length, 0); 89 90 // NB: Log after above asserts, because failures aren't propagated. 91 log.push("third return"); 92 93 // This exception is ignored. 94 throw new Test262Error(); 95 } 96 }; 97 98 function ExpectedError() {} 99 100 // Padding iterator throws from |Symbol.iterator|. 101 var padding = { 102 [Symbol.iterator]() { 103 return this; 104 }, 105 next() { 106 return {done: false}; 107 }, 108 return() { 109 log.push("padding return"); 110 111 throw new ExpectedError(); 112 }, 113 }; 114 115 assert.throws(ExpectedError, function() { 116 Iterator.zip([first, second, third], {mode: "longest", padding}); 117 }); 118 119 assert.compareArray(log, [ 120 "padding return", 121 "third return", 122 "second return", 123 "first return", 124 ]); 125 126 reportCompare(0, 0);