mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-21 06:37:30 +09:00
Close iterator after error in {Map,Set,WeakMap,WeakSet} constructors
Issue #17
This commit is contained in:
parent
3271333633
commit
a32ecd025a
6 changed files with 306 additions and 6 deletions
|
|
@ -40,11 +40,18 @@ function MapConstructorInit(iterable) {
|
||||||
var nextItem = next.value;
|
var nextItem = next.value;
|
||||||
|
|
||||||
// Step 8.d.
|
// Step 8.d.
|
||||||
if (!IsObject(nextItem))
|
if (!IsObject(nextItem)) {
|
||||||
|
IteratorCloseThrow(iter);
|
||||||
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Map");
|
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Map");
|
||||||
|
}
|
||||||
|
|
||||||
// Steps 8.e-j.
|
// Steps 8.e-j.
|
||||||
callContentFunction(adder, map, nextItem[0], nextItem[1]);
|
try {
|
||||||
|
callContentFunction(adder, map, nextItem[0], nextItem[1]);
|
||||||
|
} catch (e) {
|
||||||
|
IteratorCloseThrow(iter);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,12 @@ function SetConstructorInit(iterable) {
|
||||||
var nextValue = next.value;
|
var nextValue = next.value;
|
||||||
|
|
||||||
// Steps 8.d-e.
|
// Steps 8.d-e.
|
||||||
callContentFunction(adder, set, nextValue);
|
try {
|
||||||
|
callContentFunction(adder, set, nextValue);
|
||||||
|
} catch (e) {
|
||||||
|
IteratorCloseThrow(iter);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,29 @@ function GetIterator(obj, method) {
|
||||||
return iterator;
|
return iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ES2017 draft rev 7.4.6.
|
||||||
|
// When completion.[[Type]] is throw.
|
||||||
|
function IteratorCloseThrow(iter) {
|
||||||
|
// Steps 1-2 (implicit)
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
var returnMethod = GetMethod(iter, "return");
|
||||||
|
|
||||||
|
// Step 4 (done in caller).
|
||||||
|
if (returnMethod === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Step 5.
|
||||||
|
callContentFunction(returnMethod, iter);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6 (done in caller).
|
||||||
|
|
||||||
|
// Steps 7-9 (skipped).
|
||||||
|
}
|
||||||
|
|
||||||
var _builtinCtorsCache = {__proto__: null};
|
var _builtinCtorsCache = {__proto__: null};
|
||||||
|
|
||||||
function GetBuiltinConstructor(builtinName) {
|
function GetBuiltinConstructor(builtinName) {
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,17 @@ function WeakMapConstructorInit(iterable) {
|
||||||
var nextItem = next.value;
|
var nextItem = next.value;
|
||||||
|
|
||||||
// Step 8.d.
|
// Step 8.d.
|
||||||
if (!IsObject(nextItem))
|
if (!IsObject(nextItem)) {
|
||||||
|
IteratorCloseThrow(iter);
|
||||||
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "WeakMap");
|
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "WeakMap");
|
||||||
|
}
|
||||||
|
|
||||||
// Steps 8.e-j.
|
// Steps 8.e-j.
|
||||||
callContentFunction(adder, map, nextItem[0], nextItem[1]);
|
try {
|
||||||
|
callContentFunction(adder, map, nextItem[0], nextItem[1]);
|
||||||
|
} catch (e) {
|
||||||
|
IteratorCloseThrow(iter);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,12 @@ function WeakSetConstructorInit(iterable) {
|
||||||
var nextValue = next.value;
|
var nextValue = next.value;
|
||||||
|
|
||||||
// Steps 8.d-e.
|
// Steps 8.d-e.
|
||||||
callContentFunction(adder, set, nextValue);
|
try {
|
||||||
|
callContentFunction(adder, set, nextValue);
|
||||||
|
} catch (e) {
|
||||||
|
IteratorCloseThrow(iter);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
253
js/src/tests/ecma_6/Map/constructor-iterator-close.js
Normal file
253
js/src/tests/ecma_6/Map/constructor-iterator-close.js
Normal file
|
|
@ -0,0 +1,253 @@
|
||||||
|
var BUGNUMBER = 1180306;
|
||||||
|
var summary = 'Map/Set/WeakMap/WeakSet constructor should close iterator on error';
|
||||||
|
|
||||||
|
print(BUGNUMBER + ": " + summary);
|
||||||
|
|
||||||
|
function test(ctors, { nextVal=undefined,
|
||||||
|
nextThrowVal=undefined,
|
||||||
|
modifier=undefined,
|
||||||
|
exceptionVal=undefined,
|
||||||
|
exceptionType=undefined,
|
||||||
|
closed=true }) {
|
||||||
|
function getIterable() {
|
||||||
|
let iterable = {
|
||||||
|
closed: false,
|
||||||
|
[Symbol.iterator]() {
|
||||||
|
let iterator = {
|
||||||
|
first: true,
|
||||||
|
next() {
|
||||||
|
if (this.first) {
|
||||||
|
this.first = false;
|
||||||
|
if (nextThrowVal)
|
||||||
|
throw nextThrowVal;
|
||||||
|
return nextVal;
|
||||||
|
}
|
||||||
|
return { value: undefined, done: true };
|
||||||
|
},
|
||||||
|
return() {
|
||||||
|
iterable.closed = true;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (modifier)
|
||||||
|
modifier(iterator, iterable);
|
||||||
|
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return iterable;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
let iterable = getIterable();
|
||||||
|
if (exceptionVal) {
|
||||||
|
let caught = false;
|
||||||
|
try {
|
||||||
|
new ctor(iterable);
|
||||||
|
} catch (e) {
|
||||||
|
assertEq(e, exceptionVal);
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assertEq(caught, true);
|
||||||
|
} else if (exceptionType) {
|
||||||
|
assertThrowsInstanceOf(() => new ctor(iterable), exceptionType);
|
||||||
|
} else {
|
||||||
|
new ctor(iterable);
|
||||||
|
}
|
||||||
|
assertEq(iterable.closed, closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// == Error cases with close ==
|
||||||
|
|
||||||
|
// ES 2017 draft 23.1.1.1 Map step 8.d.ii.
|
||||||
|
// ES 2017 draft 23.3.1.1 WeakMap step 8.d.ii.
|
||||||
|
test([Map, WeakMap], {
|
||||||
|
nextVal: { value: "non object", done: false },
|
||||||
|
exceptionType: TypeError,
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 23.1.1.1 Map step 8.f.
|
||||||
|
// ES 2017 draft 23.3.1.1 WeakMap step 8.f.
|
||||||
|
test([Map, WeakMap], {
|
||||||
|
nextVal: { value: { get 0() { throw "0 getter throws"; } }, done: false },
|
||||||
|
exceptionVal: "0 getter throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 23.1.1.1 Map step 8.h.
|
||||||
|
// ES 2017 draft 23.3.1.1 WeakMap step 8.h.
|
||||||
|
test([Map, WeakMap], {
|
||||||
|
nextVal: { value: { 0: {}, get 1() { throw "1 getter throws"; } }, done: false },
|
||||||
|
exceptionVal: "1 getter throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 23.1.1.1 Map step 8.j.
|
||||||
|
// ES 2017 draft 23.3.1.1 WeakMap step 8.j.
|
||||||
|
class MyMap extends Map {
|
||||||
|
set(k, v) {
|
||||||
|
throw "setter throws";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class MyWeakMap extends WeakMap {
|
||||||
|
set(k, v) {
|
||||||
|
throw "setter throws";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test([MyMap, MyWeakMap], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
exceptionVal: "setter throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 23.2.1.1 Set step 8.e.
|
||||||
|
// ES 2017 draft 23.4.1.1 WeakSet step 8.e.
|
||||||
|
class MySet extends Set {
|
||||||
|
add(v) {
|
||||||
|
throw "adder throws";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class MyWeakSet extends WeakSet {
|
||||||
|
add(v) {
|
||||||
|
throw "adder throws";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test([MySet, MyWeakSet], {
|
||||||
|
nextVal: { value: {}, done: false },
|
||||||
|
exceptionVal: "adder throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 7.4.6 step 3.
|
||||||
|
// if GetMethod fails, the thrown value should be used.
|
||||||
|
test([MyMap, MySet, MyWeakMap, MyWeakSet], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
Object.defineProperty(iterator, "return", {
|
||||||
|
get: function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
throw "return getter throws";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
exceptionVal: "return getter throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
test([MyMap, MySet, MyWeakMap, MyWeakSet], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
Object.defineProperty(iterator, "return", {
|
||||||
|
get: function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
return "non object";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
exceptionType: TypeError,
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
test([MyMap, MySet, MyWeakMap, MyWeakSet], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
Object.defineProperty(iterator, "return", {
|
||||||
|
get: function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
// Non callable.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
exceptionType: TypeError,
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 7.4.6 steps 6.
|
||||||
|
// if return method throws, the thrown value should be ignored.
|
||||||
|
test([MyMap, MyWeakMap], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
iterator.return = function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
throw "return throws";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
exceptionVal: "setter throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
test([MySet, MyWeakSet], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
iterator.return = function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
throw "return throws";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
exceptionVal: "adder throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
test([MyMap, MyWeakMap], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
iterator.return = function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
return "non object";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
exceptionVal: "setter throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
test([MySet, MyWeakSet], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
modifier: (iterator, iterable) => {
|
||||||
|
iterator.return = function() {
|
||||||
|
iterable.closed = true;
|
||||||
|
return "non object";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
exceptionVal: "adder throws",
|
||||||
|
closed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// == Error cases without close ==
|
||||||
|
|
||||||
|
// ES 2017 draft 23.1.1.1 Map step 8.a.
|
||||||
|
// ES 2017 draft 23.3.1.1 WeakMap step 8.a.
|
||||||
|
// ES 2017 draft 23.2.1.1 Set step 8.a.
|
||||||
|
// ES 2017 draft 23.4.1.1 WeakSet step 8.a.
|
||||||
|
test([Map, WeakMap, Set, WeakSet], {
|
||||||
|
nextThrowVal: "next throws",
|
||||||
|
exceptionVal: "next throws",
|
||||||
|
closed: false,
|
||||||
|
});
|
||||||
|
test([Map, WeakMap, Set, WeakSet], {
|
||||||
|
nextVal: { value: {}, get done() { throw "done getter throws"; } },
|
||||||
|
exceptionVal: "done getter throws",
|
||||||
|
closed: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ES 2017 draft 23.1.1.1 Map step 8.c.
|
||||||
|
// ES 2017 draft 23.3.1.1 WeakMap step 8.c.
|
||||||
|
// ES 2017 draft 23.2.1.1 Set step 8.c.
|
||||||
|
// ES 2017 draft 23.4.1.1 WeakSet step 8.c.
|
||||||
|
test([Map, WeakMap, Set, WeakSet], {
|
||||||
|
nextVal: { get value() { throw "value getter throws"; }, done: false },
|
||||||
|
exceptionVal: "value getter throws",
|
||||||
|
closed: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// == Successful cases ==
|
||||||
|
|
||||||
|
test([Map, WeakMap], {
|
||||||
|
nextVal: { value: [{}, {}], done: false },
|
||||||
|
closed: false,
|
||||||
|
});
|
||||||
|
test([Set, WeakSet], {
|
||||||
|
nextVal: { value: {}, done: false },
|
||||||
|
closed: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof reportCompare === 'function')
|
||||||
|
reportCompare(true, true);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue