Skip to content

Commit

Permalink
fix: record parenthesized identifier error for LHS
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Nov 9, 2020
1 parent 8a8e3f5 commit 00a776c
Show file tree
Hide file tree
Showing 40 changed files with 1,050 additions and 5 deletions.
22 changes: 17 additions & 5 deletions packages/babel-parser/src/parser/lval.js
Expand Up @@ -74,11 +74,23 @@ export default class LValParser extends NodeUtils {
let parenthesized = undefined;
if (node.type === "ParenthesizedExpression" || node.extra?.parenthesized) {
parenthesized = unwrapParenthesizedExpression(node);
if (
!isLHS ||
(parenthesized.type !== "Identifier" &&
parenthesized.type !== "MemberExpression")
) {
if (isLHS) {
// an LHS can be reinterpreted to a binding pattern but not vice versa.
// therefore a parenthesized identifier is ambiguous until we are sure it is an assignment expression
// i.e. `([(a) = []] = []) => {}`
// see also `recordParenthesizedIdentifierError` signature in packages/babel-parser/src/util/expression-scope.js
if (parenthesized.type === "Identifier") {
this.expressionScope.recordParenthesizedIdentifierError(
node.start,
Errors.InvalidParenthesizedAssignment,
);
} else if (parenthesized.type !== "MemberExpression") {
// A parenthesized member expression can be in LHS but not in pattern.
// If the LHS is later interpreted as a pattern, `checkLVal` will throw for member expression binding
// i.e. `([(a.b) = []] = []) => {}`
this.raise(node.start, Errors.InvalidParenthesizedAssignment);
}
} else {
this.raise(node.start, Errors.InvalidParenthesizedAssignment);
}
}
Expand Down
21 changes: 21 additions & 0 deletions packages/babel-parser/src/util/expression-scope.js
Expand Up @@ -20,6 +20,7 @@ some expression scopes and thrown later when we know what the ambigous pattern i
- AwaitBindingIdentifier
- AwaitExpressionFormalParameter
- YieldInParameter
- InvalidParenthesizedAssignment when parenthesized is an identifier
There are four different expression scope
- Expression
Expand Down Expand Up @@ -130,6 +131,26 @@ export default class ExpressionScopeHandler {
/* eslint-disable @babel/development-internal/dry-error-messages */
this.raise(pos, message);
}

/**
* Record parenthesized identifier errors
*
* A parenthesized identifier in LHS can be ambiguous because the assignment
* can be transformed to an assignable later, but not vice versa:
* For example, in `([(a) = []] = []) => {}`, we think `(a) = []` is an LHS in `[(a) = []]`,
* an LHS within `[(a) = []] = []`. However the LHS chain is then transformed by toAssignable,
* and we should throw assignment `(a)`, which is only valid in LHS. Hence we record the
* location of parenthesized `(a)` to any ancestry MaybeArrowParameterDeclaration
* and MaybeAsyncArrowParameterDeclaration scope until an Expression scope is seen
* @param {number} pos
* @param {string} message
* @returns {void}
* @memberof ExpressionScopeHandler
*/
recordParenthesizedIdentifierError(pos: number, message: string): void {
return this.recordParameterInitializerError(pos, message);
}

/**
* Record likely async arrow parameter errors
*
Expand Down
@@ -0,0 +1 @@
([ [(a)] = [] ] = []) => {}
@@ -0,0 +1,74 @@
{
"type": "File",
"start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},
"errors": [
"SyntaxError: Invalid parenthesized assignment pattern (1:5)"
],
"program": {
"type": "Program",
"start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},
"expression": {
"type": "ArrowFunctionExpression",
"start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "AssignmentPattern",
"start":1,"end":20,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":20}},
"left": {
"type": "ArrayPattern",
"start":1,"end":15,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":15}},
"elements": [
{
"type": "AssignmentPattern",
"start":3,"end":13,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":13}},
"left": {
"type": "ArrayPattern",
"start":3,"end":8,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":8}},
"elements": [
{
"type": "Identifier",
"start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"a"},
"extra": {
"parenthesized": true,
"parenStart": 4
},
"name": "a"
}
]
},
"right": {
"type": "ArrayExpression",
"start":11,"end":13,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":13}},
"elements": []
}
}
]
},
"right": {
"type": "ArrayExpression",
"start":18,"end":20,"loc":{"start":{"line":1,"column":18},"end":{"line":1,"column":20}},
"elements": []
}
}
],
"body": {
"type": "BlockStatement",
"start":25,"end":27,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":27}},
"body": [],
"directives": []
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
([(a) = [] ] = []) => {}
@@ -0,0 +1,68 @@
{
"type": "File",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":24}},
"errors": [
"SyntaxError: Invalid parenthesized assignment pattern (1:3)"
],
"program": {
"type": "Program",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":24}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":24}},
"expression": {
"type": "ArrowFunctionExpression",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":24}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "AssignmentPattern",
"start":1,"end":17,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":17}},
"left": {
"type": "ArrayPattern",
"start":1,"end":12,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":12}},
"elements": [
{
"type": "AssignmentPattern",
"start":2,"end":10,"loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":10}},
"left": {
"type": "Identifier",
"start":3,"end":4,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4},"identifierName":"a"},
"extra": {
"parenthesized": true,
"parenStart": 2
},
"name": "a"
},
"right": {
"type": "ArrayExpression",
"start":8,"end":10,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":10}},
"elements": []
}
}
]
},
"right": {
"type": "ArrayExpression",
"start":15,"end":17,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":17}},
"elements": []
}
}
],
"body": {
"type": "BlockStatement",
"start":22,"end":24,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":24}},
"body": [],
"directives": []
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
({ a: (foo.qux) } = {}) => {}
@@ -0,0 +1,81 @@
{
"type": "File",
"start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},
"errors": [
"SyntaxError: Binding member expression (1:7)"
],
"program": {
"type": "Program",
"start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},
"expression": {
"type": "ArrowFunctionExpression",
"start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "AssignmentPattern",
"start":1,"end":22,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":22}},
"left": {
"type": "ObjectPattern",
"start":1,"end":17,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":17}},
"properties": [
{
"type": "ObjectProperty",
"start":3,"end":15,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":15}},
"method": false,
"key": {
"type": "Identifier",
"start":3,"end":4,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4},"identifierName":"a"},
"name": "a"
},
"computed": false,
"shorthand": false,
"value": {
"type": "MemberExpression",
"start":7,"end":14,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":14}},
"extra": {
"parenthesized": true,
"parenStart": 6
},
"object": {
"type": "Identifier",
"start":7,"end":10,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":10},"identifierName":"foo"},
"name": "foo"
},
"computed": false,
"property": {
"type": "Identifier",
"start":11,"end":14,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":14},"identifierName":"qux"},
"name": "qux"
}
}
}
]
},
"right": {
"type": "ObjectExpression",
"start":20,"end":22,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":22}},
"properties": []
}
}
],
"body": {
"type": "BlockStatement",
"start":27,"end":29,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":29}},
"body": [],
"directives": []
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
({ a: (foo) } = {}) => {}
@@ -0,0 +1,71 @@
{
"type": "File",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
"errors": [
"SyntaxError: Invalid parenthesized assignment pattern (1:7)"
],
"program": {
"type": "Program",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
"expression": {
"type": "ArrowFunctionExpression",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "AssignmentPattern",
"start":1,"end":18,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":18}},
"left": {
"type": "ObjectPattern",
"start":1,"end":13,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":13}},
"properties": [
{
"type": "ObjectProperty",
"start":3,"end":11,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":11}},
"method": false,
"key": {
"type": "Identifier",
"start":3,"end":4,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4},"identifierName":"a"},
"name": "a"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start":7,"end":10,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":10},"identifierName":"foo"},
"extra": {
"parenthesized": true,
"parenStart": 6
},
"name": "foo"
}
}
]
},
"right": {
"type": "ObjectExpression",
"start":16,"end":18,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":18}},
"properties": []
}
}
],
"body": {
"type": "BlockStatement",
"start":23,"end":25,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":25}},
"body": [],
"directives": []
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
([(a) = [] ] = []);

0 comments on commit 00a776c

Please sign in to comment.