blob: 652f8ed2d4b722296a2db6832db2eda3e69363a2 [file] [edit]
function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error(`FAIL: expected ${expected}, got ${actual}`);
}
function shouldNotInclude(string, substring) {
if (string.includes(substring))
throw new Error(`FAIL: ${JSON.stringify(string)} should not include ${JSON.stringify(substring)}`);
}
// When the subject of an iteration construct is a constant that does not itself
// emit expression info (e.g. a null literal), the [Symbol.iterator] get_by_id /
// op_spread should still be attributed to the iterating construct, not to the
// previous statement.
function check(prefix, body) {
let source = `(${prefix} () {
"sentinelStatement";
${body}
})`;
let f = eval(source);
let error = null;
let onError = e => { error = e; };
try {
let result = f();
if (prefix === "function*")
result.next();
else if (prefix === "async function") {
result.catch(onError);
drainMicrotasks();
}
} catch (e) {
onError(e);
}
if (!error)
throw new Error(`FAIL: ${body} did not throw`);
shouldBe(error.line, 3);
shouldNotInclude(error.message, "sentinelStatement");
}
check("function", `for (const b of null) {}`);
check("function", `for (const b of undefined) {}`);
check("function", `const [a] = null;`);
check("function", `var a = [...null];`);
check("function", `var a = [1, ...null, 2];`);
check("function", `Array(...[...null]);`);
check("function", `new Array(...[...null]);`);
check("function*", `yield* null;`);
check("async function", `for await (const b of null) {}`);