tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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);