Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly check for-in and for-of loop for invalid left-hand side #9768

Merged
merged 2 commits into from Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 31 additions & 23 deletions packages/babel-parser/src/parser/statement.js
Expand Up @@ -519,21 +519,11 @@ export default class StatementParser extends ExpressionParser {
this.parseVar(init, true, kind);
this.finishNode(init, "VariableDeclaration");

if (this.match(tt._in) || this.isContextual("of")) {
if (init.declarations.length === 1) {
const declaration = init.declarations[0];
const isForInInitializer =
kind === "var" &&
declaration.init &&
declaration.id.type != "ObjectPattern" &&
declaration.id.type != "ArrayPattern" &&
!this.isContextual("of");
if (this.state.strict && isForInInitializer) {
this.raise(this.state.start, "for-in initializer in strict mode");
} else if (isForInInitializer || !declaration.init) {
return this.parseForIn(node, init, awaitAt);
}
}
if (
(this.match(tt._in) || this.isContextual("of")) &&
init.declarations.length === 1
) {
return this.parseForIn(node, init, awaitAt);
}
if (awaitAt > -1) {
this.unexpected(awaitAt);
Expand Down Expand Up @@ -938,18 +928,36 @@ export default class StatementParser extends ExpressionParser {

parseForIn(
node: N.ForInOf,
init: N.VariableDeclaration,
init: N.VariableDeclaration | N.AssignmentPattern,
awaitAt: number,
): N.ForInOf {
const type = this.match(tt._in) ? "ForInStatement" : "ForOfStatement";
if (awaitAt > -1) {
this.eatContextual("of");
const isForIn = this.match(tt._in);
this.next();

if (isForIn) {
if (awaitAt > -1) this.unexpected(awaitAt);
} else {
this.next();
}
if (type === "ForOfStatement") {
node.await = awaitAt > -1;
}

if (
init.type === "VariableDeclaration" &&
init.declarations[0].init != null &&
(!isForIn ||
this.state.strict ||
init.kind !== "var" ||
init.declarations[0].id.type !== "Identifier")
) {
this.raise(
init.start,
`${
isForIn ? "for-in" : "for-of"
} loop variable declaration may not have an initializer`,
);
} else if (init.type === "AssignmentPattern") {
this.raise(init.start, "Invalid left-hand side in for-loop");
}

node.left = init;
node.right = this.parseExpression();
this.expect(tt.parenR);
Expand All @@ -966,7 +974,7 @@ export default class StatementParser extends ExpressionParser {
this.scope.exit();
this.state.labels.pop();

return this.finishNode(node, type);
return this.finishNode(node, isForIn ? "ForInStatement" : "ForOfStatement");
}

// Parse a list of variable declarations.
Expand Down
@@ -0,0 +1,3 @@
{
"throws": "Invalid left-hand side in for-loop (2:5)"
}

This file was deleted.

@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:17)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:15)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "for-in initializer in strict mode (2:15)"
}
"throws": "for-in loop variable declaration may not have an initializer (2:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:17)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:17)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
@@ -0,0 +1,2 @@
var a;
for (a = 0 of {});
@@ -0,0 +1,3 @@
{
"throws": "Invalid left-hand side in for-loop (2:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:16)"
}
"throws": "for-of loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:16)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:16)"
}
"throws": "for-of loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token (2:19)"
}
"throws": "Unexpected token (2:6)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:17)"
}
"throws": "for-of loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:15)"
}
"throws": "for-of loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:15)"
}
"throws": "for-of loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:17)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:15)"
}
"throws": "for-in loop variable declaration may not have an initializer (1:5)"
}
6 changes: 6 additions & 0 deletions packages/babel-parser/test/helpers/runFixtureTests.js
Expand Up @@ -131,6 +131,12 @@ function runTest(test, parseFunction) {
if (err.message === opts.throws) {
return;
} else {
/*
const fn = path.dirname(test.expect.loc) + "/options.json";
danez marked this conversation as resolved.
Show resolved Hide resolved
test.options = test.options || {};
test.options.throws = err.message;
fs.writeFileSync(fn, JSON.stringify(test.options, null, " "));
*/
err.message =
"Expected error message: " +
opts.throws +
Expand Down
2 changes: 0 additions & 2 deletions scripts/tests/test262/test262_whitelist.txt
@@ -1,5 +1,3 @@
annexB/language/statements/for-in/bare-initializer.js(default)
annexB/language/statements/for-in/bare-initializer.js(strict mode)
built-ins/RegExp/property-escapes/binary-property-with-value-ASCII_-_F-negated.js(default)
built-ins/RegExp/property-escapes/binary-property-with-value-ASCII_-_F-negated.js(strict mode)
built-ins/RegExp/property-escapes/binary-property-with-value-ASCII_-_F.js(default)
Expand Down