fix: disallow all parenthesized pattern except parsing LHS (#12327)

* fix: disallow all parenthesized pattern except parsing LHS

* fix: forStatement requires LHS

* simplify toAssignable

* add more test cases

* fix: pass through isLHS on object property and assignment expression

* fix: record parenthesized identifier error for LHS

* remove duplicated skipped tests

* fix: do not record errors on ancestry arrow head

* Update packages/babel-parser/src/util/expression-scope.js

Co-authored-by: Brian Ng <bng412@gmail.com>

Co-authored-by: Brian Ng <bng412@gmail.com>
This commit is contained in:
Huáng Jùnliàng
2020-11-10 14:42:37 -05:00
committed by GitHub
parent 08c7280167
commit 5bbad8936b
93 changed files with 2273 additions and 115 deletions

View File

@@ -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
@@ -130,6 +131,41 @@ 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 current scope if it is one of MaybeArrowParameterDeclaration
* and MaybeAsyncArrowParameterDeclaration
*
* Unlike `recordParameterInitializerError`, we don't record to ancestry scope because we
* validate arrow head parsing scope before exit, and then the LHS will be unambiguous:
* For example, in `( x = ( [(a) = []] = [] ) ) => {}`, we should not record `(a)` in `( x = ... ) =>`
* arrow scope because when we finish parsing `( [(a) = []] = [] )`, it is an unambiguous assignment
* expression and can not be cast to pattern
* @param {number} pos
* @param {string} message
* @returns {void}
* @memberof ExpressionScopeHandler
*/
recordParenthesizedIdentifierError(pos: number, message: string): void {
const { stack } = this;
const scope: ExpressionScope = stack[stack.length - 1];
if (scope.isCertainlyParameterDeclaration()) {
this.raise(pos, message);
} else if (scope.canBeArrowParameterDeclaration()) {
/*:: invariant(scope instanceof ArrowHeadParsingScope) */
scope.recordDeclarationError(pos, message);
} else {
return;
}
}
/**
* Record likely async arrow parameter errors
*