Skip to content

Commit adfc494

Browse files
committed
fix proxying .return() on exhausted iterator from some methods of iterator helpers polyfill to the underlying iterator
1 parent 3a12ef6 commit adfc494

File tree

4 files changed

+38
-3
lines changed

4 files changed

+38
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
- Wrap `Symbol.for` in `Symbol.prototype.description` polyfill for correct handling of empty string descriptions
1010
- Fixed one more case (`Iterator.prototype.take`) of a V8 ~ Chromium < 126 [bug](https://issues.chromium.org/issues/336839115)
1111
- Forced replacement of `Iterator.{ concat, zip, zipKeyed }` in the pure version for ensuring proper wrapped `Iterator` instances as the result
12-
- Fixed double `.return` calling in case of throwing error in this method in the internal `iterate` helper that affected some polyfills
12+
- Fixed proxying `.return()` on exhausted iterator from some methods of iterator helpers polyfill to the underlying iterator
13+
- Fixed double `.return()` calling in case of throwing error in this method in the internal `iterate` helper that affected some polyfills
1314
- Fixed closing iterator on `IteratorValue` errors in the internal `iterate` helper that affected some polyfills
1415
- Fixed iterator closing in `Array.from` polyfill on failure to create array property
1516
- Fixed some cases of iterators closing in `Iterator.{ zip, zipKeyed }` polyfills
@@ -52,9 +53,9 @@
5253
- Fixed counter in some cases of some `AsyncIterator` methods
5354
- Fixed order of async iterators closing
5455
- Fixed iterator closing in `AsyncIterator.prototype.flatMap` polyfill
55-
- Fixed iterator closing in `AsyncIterator.prototype.map` polyfill on error in inner iterator `.next`
56+
- Fixed iterator closing in `AsyncIterator.prototype.map` polyfill on error in underlying iterator `.next()`
5657
- Fixed iterator closing in `AsyncIterator.prototype.take` polyfill with `return: null`
57-
- Fixed validation `return()` result as object in `AsyncIterator.prototype.take` polyfill
58+
- Fixed validation `.return()` result as object in `AsyncIterator.prototype.take` polyfill
5859
- Fixed a lack of error in `structuredClone` polyfill on attempt to transfer multiple objects, some of which are non-transferable
5960
- Fixed resizable `ArrayBuffer` transferring where `newByteLength` exceeds the original `maxByteLength`
6061
- Fixed possible loss of symbol enumerability in `Object.defineProperty` in `Symbol` polyfill

packages/core-js/internals/iterator-create-proxy.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ var createIteratorProxyPrototype = function (IS_ITERATOR) {
4040
'return': function () {
4141
var state = getInternalState(this);
4242
var iterator = state.iterator;
43+
var done = state.done;
4344
state.done = true;
4445
if (IS_ITERATOR) {
4546
var returnMethod = getMethod(iterator, 'return');
4647
return returnMethod ? call(returnMethod, iterator) : createIterResultObject(undefined, true);
4748
}
49+
if (done) return createIterResultObject(undefined, true);
4850
if (state.inner) try {
4951
iteratorClose(state.inner.iterator, NORMAL);
5052
} catch (error) {

tests/unit-global/es.iterator.map.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ QUnit.test('Iterator#map', assert => {
3030
const it = createIterator([1], { return() { this.closed = true; } });
3131
assert.throws(() => map.call(it, {}), TypeError);
3232
assert.true(it.closed, 'map closes iterator on validation error');
33+
34+
{
35+
let returnCount = 0;
36+
const it2 = createIterator([1], {
37+
return() {
38+
returnCount++;
39+
return { done: true, value: undefined };
40+
},
41+
});
42+
const mapped = map.call(it2, x => x);
43+
mapped.next();
44+
mapped.next(); // exhaust
45+
mapped.return();
46+
assert.same(returnCount, 0, '.return() on exhausted iterator does not call underlying return');
47+
}
48+
3349
// https://issues.chromium.org/issues/336839115
3450
assert.throws(() => map.call({ next: null }, () => { /* empty */ }).next(), TypeError);
3551
});

tests/unit-pure/es.iterator.map.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ QUnit.test('Iterator#map', assert => {
3030
const it = createIterator([1], { return() { this.closed = true; } });
3131
assert.throws(() => map.call(it, {}), TypeError);
3232
assert.true(it.closed, 'map closes iterator on validation error');
33+
34+
{
35+
let returnCount = 0;
36+
const it2 = createIterator([1], {
37+
return() {
38+
returnCount++;
39+
return { done: true, value: undefined };
40+
},
41+
});
42+
const mapped = map.call(it2, x => x);
43+
mapped.next();
44+
mapped.next(); // exhaust
45+
mapped.return();
46+
assert.same(returnCount, 0, '.return() on exhausted iterator does not call underlying return');
47+
}
48+
3349
// https://issues.chromium.org/issues/336839115
3450
assert.throws(() => map.call({ next: null }, () => { /* empty */ }).next(), TypeError);
3551
});

0 commit comments

Comments
 (0)