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
[parser] validation for parentheses in the left-hand side of assignment expressions #10576
Conversation
prop, | ||
isBinding, | ||
isLast, | ||
allowAssign, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it passed down? Inside an object property, assignments are always allowed (for default props)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original approach needed to pass it down to "remember" that there had been a parenthesis somewhere up the stack - to invalidate expressions such as [({ a: [b = 2]})] = t
. It's become more clear to me now that the presence of certain parenthesis in the left-hand side of an assignment expression is the problem so I'll clean this up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While playing in the repl, I found another case which is deeply related to this one:
[([x])] = y;
I know that I wrote the hint you followed to implement this PR, but I now think that there could be a better way of doing it 😅
Since parenthesized assignment target are the exception, and they should only be allowed in a top-level target (i.e. not inside a destructuring), I think that we can pass a isParenthesized
flag instead of allowAssign
and:
- If it isn't set, you should set it to
node.extra?.parenthesized
using a default param - If
isParenthesized
is true and the current node type is notMemberExpression
orIdentifier
, throw an error (e.g.Invalid parenthesized assignment pattern
).
Note that the isParenthesized
parameter should be set to true only when converting the child a ParenthesizedExpression
6807302
to
7e158a1
Compare
@@ -1,3 +1,3 @@ | |||
{ | |||
"throws": "You're trying to assign to a parenthesized expression, eg. instead of `([a]) = 0` use `([a] = 0)` (1:1)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We lose this specific error message by applying a more general fix but I think it's probably worth it in terms of code cleanliness - messages for specific cases can be added as an extension.
@nicolo-ribaudo makes sense - I've updated the code. I think we can get away with not having an extra parameter in The new logic covers most of the parens validation needed except for when the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new logic covers most of the parens validation needed except for when the createParenthesizedExpressions parser option is set to true
So it still doesn't throw the error in that case?
@nicolo-ribaudo @JLHwung originally I thought there might need to be a separate flow for handling the Edit: looks like tests may be failing due to a memory issue - |
@@ -19,6 +19,12 @@ import { isStrictBindReservedWord } from "../util/identifier"; | |||
import { NodeUtils } from "./node"; | |||
import { type BindingTypes, BIND_NONE } from "../util/scopeflags"; | |||
|
|||
const unwrapParenthesizedExpression = (node: Node) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is needed to handle nested parenthesis when createParenthesizedExpressions
is enabled. i.e. [(((x)))]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For nested parenthesis, toAssignable
will be called with parenthesizee recursively. Therefore we may check if node.expression
is one of Identifier
, MemberExpression
and ParenthesizedExpression
.
@boweihan Circle CI is flaky. I have rerun the build. |
484a6d6
to
b1ca931
Compare
@boweihan Well done! Thanks. |
@nicolo-ribaudo has a good description of the problem in the linked issue. Basically, the parser is missing some validation for parentheses in the left-hand side of assignment expressions.
This means that expressions such as
[a = 1] = t
and[ { x: y = 3 } ] = t
are valid (and correctly so!).The issue with the current behaviour is that expressions such as 1:
(a = 1) = t
and 2:[(a = 1)] = t
are treated as valid. The left-hand side of assignment expressions should be invalid if there are any parenthesized child nodes which are not of typeIdentifier
orMemberExpression
.The fix in this pr involves:
toAssignable