From d187c267481a1436bbbb077d5dd94f191e6ef72a Mon Sep 17 00:00:00 2001 From: K Sashi Kumar Date: Mon, 5 Mar 2018 05:48:32 +0530 Subject: [PATCH] Spec Violation: Fix var initializer in for-in loop (#7392) --- packages/babylon/src/parser/statement.js | 15 +- .../es2015/for-in/bare-initializer/input.js | 2 + .../for-in/bare-initializer/output.json | 183 +++++ .../es2015/for-in/const-initializer/input.js | 1 + .../for-in/const-initializer/options.json | 3 + .../es2015/for-in/let-initializer/input.js | 1 + .../for-in/let-initializer/options.json | 3 + .../for-in/nonstrict-initializer/input.js | 6 + .../for-in/nonstrict-initializer/output.json | 707 ++++++++++++++++++ .../es2015/for-in/strict-initializer/input.js | 2 + .../for-in/strict-initializer/options.json | 3 + .../input.js | 1 + .../options.json | 3 + .../input.js | 1 + .../options.json | 3 + scripts/tests/test262/test262_whitelist.txt | 1 - 16 files changed, 932 insertions(+), 3 deletions(-) create mode 100644 packages/babylon/test/fixtures/es2015/for-in/bare-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/bare-initializer/output.json create mode 100644 packages/babylon/test/fixtures/es2015/for-in/const-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/const-initializer/options.json create mode 100644 packages/babylon/test/fixtures/es2015/for-in/let-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/let-initializer/options.json create mode 100644 packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/output.json create mode 100644 packages/babylon/test/fixtures/es2015/for-in/strict-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/strict-initializer/options.json create mode 100644 packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json create mode 100644 packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/input.js create mode 100644 packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json diff --git a/packages/babylon/src/parser/statement.js b/packages/babylon/src/parser/statement.js index d736b46184..cd8a9efbea 100644 --- a/packages/babylon/src/parser/statement.js +++ b/packages/babylon/src/parser/statement.js @@ -367,8 +367,19 @@ export default class StatementParser extends ExpressionParser { this.finishNode(init, "VariableDeclaration"); if (this.match(tt._in) || this.isContextual("of")) { - if (init.declarations.length === 1 && !init.declarations[0].init) { - return this.parseForIn(node, init, forAwait); + if (init.declarations.length === 1) { + const declaration = init.declarations[0]; + const isForInInitializer = + varKind === tt._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, forAwait); + } } } if (forAwait) { diff --git a/packages/babylon/test/fixtures/es2015/for-in/bare-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/bare-initializer/input.js new file mode 100644 index 0000000000..094f22863b --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/bare-initializer/input.js @@ -0,0 +1,2 @@ +var a; +for (a = 0 in {}); diff --git a/packages/babylon/test/fixtures/es2015/for-in/bare-initializer/output.json b/packages/babylon/test/fixtures/es2015/for-in/bare-initializer/output.json new file mode 100644 index 0000000000..b205c87f55 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/bare-initializer/output.json @@ -0,0 +1,183 @@ +{ + "type": "File", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "sourceType": "script", + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 5, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 5 + } + }, + "id": { + "type": "Identifier", + "start": 4, + "end": 5, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 5 + }, + "identifierName": "a" + }, + "name": "a" + }, + "init": null + } + ], + "kind": "var" + }, + { + "type": "ForInStatement", + "start": 7, + "end": 25, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "left": { + "type": "AssignmentPattern", + "start": 12, + "end": 17, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "left": { + "type": "Identifier", + "start": 12, + "end": 13, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 6 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "NumericLiteral", + "start": 16, + "end": 17, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + } + }, + "right": { + "type": "ObjectExpression", + "start": 21, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "properties": [] + }, + "body": { + "type": "EmptyStatement", + "start": 24, + "end": 25, + "loc": { + "start": { + "line": 2, + "column": 17 + }, + "end": { + "line": 2, + "column": 18 + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/const-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/const-initializer/input.js new file mode 100644 index 0000000000..aa7bc09da8 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/const-initializer/input.js @@ -0,0 +1 @@ +for (const a = 0 in {}); \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/const-initializer/options.json b/packages/babylon/test/fixtures/es2015/for-in/const-initializer/options.json new file mode 100644 index 0000000000..a7c6e79257 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/const-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected \";\" (1:17)" +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/let-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/let-initializer/input.js new file mode 100644 index 0000000000..037f0d3403 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/let-initializer/input.js @@ -0,0 +1 @@ +for (let a = 0 in {}); \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/let-initializer/options.json b/packages/babylon/test/fixtures/es2015/for-in/let-initializer/options.json new file mode 100644 index 0000000000..bc625e0d0c --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/let-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected \";\" (1:15)" +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/input.js new file mode 100644 index 0000000000..c2b56cda95 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/input.js @@ -0,0 +1,6 @@ + var effects = 0; + var iterations = 0; + var stored; + for (var a = (++effects, -1) in stored = a, {a: 0, b: 1, c: 2}) { + ++iterations; + } diff --git a/packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/output.json b/packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/output.json new file mode 100644 index 0000000000..4e0e704c37 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/nonstrict-initializer/output.json @@ -0,0 +1,707 @@ +{ + "type": "File", + "start": 0, + "end": 144, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 144, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "sourceType": "script", + "body": [ + { + "type": "VariableDeclaration", + "start": 2, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 6, + "end": 17, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 17 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "effects" + }, + "name": "effects" + }, + "init": { + "type": "NumericLiteral", + "start": 16, + "end": 17, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + }, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + } + } + ], + "kind": "var" + }, + { + "type": "VariableDeclaration", + "start": 21, + "end": 40, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 21 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 25, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 6 + }, + "end": { + "line": 2, + "column": 20 + } + }, + "id": { + "type": "Identifier", + "start": 25, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 6 + }, + "end": { + "line": 2, + "column": 16 + }, + "identifierName": "iterations" + }, + "name": "iterations" + }, + "init": { + "type": "NumericLiteral", + "start": 38, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 2, + "column": 20 + } + }, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + } + } + ], + "kind": "var" + }, + { + "type": "VariableDeclaration", + "start": 43, + "end": 54, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 13 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 47, + "end": 53, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 12 + } + }, + "id": { + "type": "Identifier", + "start": 47, + "end": 53, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 12 + }, + "identifierName": "stored" + }, + "name": "stored" + }, + "init": null + } + ], + "kind": "var" + }, + { + "type": "ForInStatement", + "start": 57, + "end": 144, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "left": { + "type": "VariableDeclaration", + "start": 62, + "end": 85, + "loc": { + "start": { + "line": 4, + "column": 7 + }, + "end": { + "line": 4, + "column": 30 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 66, + "end": 85, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 30 + } + }, + "id": { + "type": "Identifier", + "start": 66, + "end": 67, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 12 + }, + "identifierName": "a" + }, + "name": "a" + }, + "init": { + "type": "SequenceExpression", + "start": 71, + "end": 84, + "loc": { + "start": { + "line": 4, + "column": 16 + }, + "end": { + "line": 4, + "column": 29 + } + }, + "expressions": [ + { + "type": "UpdateExpression", + "start": 71, + "end": 80, + "loc": { + "start": { + "line": 4, + "column": 16 + }, + "end": { + "line": 4, + "column": 25 + } + }, + "operator": "++", + "prefix": true, + "argument": { + "type": "Identifier", + "start": 73, + "end": 80, + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 25 + }, + "identifierName": "effects" + }, + "name": "effects" + }, + "extra": { + "parenthesizedArgument": false + } + }, + { + "type": "UnaryExpression", + "start": 82, + "end": 84, + "loc": { + "start": { + "line": 4, + "column": 27 + }, + "end": { + "line": 4, + "column": 29 + } + }, + "operator": "-", + "prefix": true, + "argument": { + "type": "NumericLiteral", + "start": 83, + "end": 84, + "loc": { + "start": { + "line": 4, + "column": 28 + }, + "end": { + "line": 4, + "column": 29 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + }, + "extra": { + "parenthesizedArgument": false + } + } + ], + "extra": { + "parenthesized": true, + "parenStart": 70 + } + } + } + ], + "kind": "var" + }, + "right": { + "type": "SequenceExpression", + "start": 89, + "end": 119, + "loc": { + "start": { + "line": 4, + "column": 34 + }, + "end": { + "line": 4, + "column": 64 + } + }, + "expressions": [ + { + "type": "AssignmentExpression", + "start": 89, + "end": 99, + "loc": { + "start": { + "line": 4, + "column": 34 + }, + "end": { + "line": 4, + "column": 44 + } + }, + "operator": "=", + "left": { + "type": "Identifier", + "start": 89, + "end": 95, + "loc": { + "start": { + "line": 4, + "column": 34 + }, + "end": { + "line": 4, + "column": 40 + }, + "identifierName": "stored" + }, + "name": "stored" + }, + "right": { + "type": "Identifier", + "start": 98, + "end": 99, + "loc": { + "start": { + "line": 4, + "column": 43 + }, + "end": { + "line": 4, + "column": 44 + }, + "identifierName": "a" + }, + "name": "a" + } + }, + { + "type": "ObjectExpression", + "start": 101, + "end": 119, + "loc": { + "start": { + "line": 4, + "column": 46 + }, + "end": { + "line": 4, + "column": 64 + } + }, + "properties": [ + { + "type": "ObjectProperty", + "start": 102, + "end": 106, + "loc": { + "start": { + "line": 4, + "column": 47 + }, + "end": { + "line": 4, + "column": 51 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 102, + "end": 103, + "loc": { + "start": { + "line": 4, + "column": 47 + }, + "end": { + "line": 4, + "column": 48 + }, + "identifierName": "a" + }, + "name": "a" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "NumericLiteral", + "start": 105, + "end": 106, + "loc": { + "start": { + "line": 4, + "column": 50 + }, + "end": { + "line": 4, + "column": 51 + } + }, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + } + }, + { + "type": "ObjectProperty", + "start": 108, + "end": 112, + "loc": { + "start": { + "line": 4, + "column": 53 + }, + "end": { + "line": 4, + "column": 57 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 108, + "end": 109, + "loc": { + "start": { + "line": 4, + "column": 53 + }, + "end": { + "line": 4, + "column": 54 + }, + "identifierName": "b" + }, + "name": "b" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "NumericLiteral", + "start": 111, + "end": 112, + "loc": { + "start": { + "line": 4, + "column": 56 + }, + "end": { + "line": 4, + "column": 57 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ObjectProperty", + "start": 114, + "end": 118, + "loc": { + "start": { + "line": 4, + "column": 59 + }, + "end": { + "line": 4, + "column": 63 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 114, + "end": 115, + "loc": { + "start": { + "line": 4, + "column": 59 + }, + "end": { + "line": 4, + "column": 60 + }, + "identifierName": "c" + }, + "name": "c" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "NumericLiteral", + "start": 117, + "end": 118, + "loc": { + "start": { + "line": 4, + "column": 62 + }, + "end": { + "line": 4, + "column": 63 + } + }, + "extra": { + "rawValue": 2, + "raw": "2" + }, + "value": 2 + } + } + ] + } + ] + }, + "body": { + "type": "BlockStatement", + "start": 121, + "end": 144, + "loc": { + "start": { + "line": 4, + "column": 66 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 127, + "end": 140, + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 17 + } + }, + "expression": { + "type": "UpdateExpression", + "start": 127, + "end": 139, + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 16 + } + }, + "operator": "++", + "prefix": true, + "argument": { + "type": "Identifier", + "start": 129, + "end": 139, + "loc": { + "start": { + "line": 5, + "column": 6 + }, + "end": { + "line": 5, + "column": 16 + }, + "identifierName": "iterations" + }, + "name": "iterations" + }, + "extra": { + "parenthesizedArgument": false + } + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/strict-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/strict-initializer/input.js new file mode 100644 index 0000000000..c1ecfdf85c --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/strict-initializer/input.js @@ -0,0 +1,2 @@ +'use strict'; +for (var a = 0 in {}); \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/strict-initializer/options.json b/packages/babylon/test/fixtures/es2015/for-in/strict-initializer/options.json new file mode 100644 index 0000000000..983e17a01e --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/strict-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "for-in initializer in strict mode (2:15)" +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/input.js new file mode 100644 index 0000000000..54b71b26a4 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/input.js @@ -0,0 +1 @@ +for (var [a] = 0 in {}); \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json b/packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json new file mode 100644 index 0000000000..a7c6e79257 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected \";\" (1:17)" +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/input.js b/packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/input.js new file mode 100644 index 0000000000..f0708b2348 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/input.js @@ -0,0 +1 @@ +for (var {a} = 0 in {}); \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json b/packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json new file mode 100644 index 0000000000..a7c6e79257 --- /dev/null +++ b/packages/babylon/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected \";\" (1:17)" +} \ No newline at end of file diff --git a/scripts/tests/test262/test262_whitelist.txt b/scripts/tests/test262/test262_whitelist.txt index 2f6696503c..e7e03f746b 100644 --- a/scripts/tests/test262/test262_whitelist.txt +++ b/scripts/tests/test262/test262_whitelist.txt @@ -610,7 +610,6 @@ annexB/language/global-code/if-stmt-else-decl-global-skip-early-err-switch.js(de annexB/language/global-code/if-stmt-else-decl-global-skip-early-err-try.js(default) annexB/language/global-code/if-stmt-else-decl-global-skip-early-err.js(default) annexB/language/global-code/if-stmt-else-decl-global-update.js(default) -annexB/language/statements/for-in/nonstrict-initializer.js(default) built-ins/Function/prototype/toString/intrinsics.js(strict mode) language/expressions/assignment/destructuring/obj-prop-__proto__dup.js(default) language/expressions/assignment/destructuring/obj-prop-__proto__dup.js(strict mode)