Evaluate RHS of binding/assignment pattern first (#34806)

This commit is contained in:
Ron Buckton
2019-10-29 17:42:30 -07:00
committed by GitHub
parent 00dd1f0609
commit 87cc8c4af8
12 changed files with 62 additions and 43 deletions

View File

@@ -5389,6 +5389,12 @@ namespace ts {
* Gets the property name of a BindingOrAssignmentElement
*/
export function getPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): PropertyName | undefined {
const propertyName = tryGetPropertyNameOfBindingOrAssignmentElement(bindingElement);
Debug.assert(!!propertyName || isSpreadAssignment(bindingElement), "Invalid property name for binding element.");
return propertyName;
}
export function tryGetPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): PropertyName | undefined {
switch (bindingElement.kind) {
case SyntaxKind.BindingElement:
// `a` in `let { a: b } = ...`
@@ -5429,8 +5435,6 @@ namespace ts {
? target.expression
: target;
}
Debug.fail("Invalid property name for binding element.");
}
function isStringOrNumericLiteral(node: Node): node is StringLiteral | NumericLiteral {

View File

@@ -68,7 +68,8 @@ namespace ts {
if (value) {
value = visitNode(value, visitor, isExpression);
if (isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText)) {
if (isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) ||
bindingOrAssignmentElementContainsNonLiteralComputedName(node)) {
// If the right-hand value of the assignment is also an assignment target then
// we need to cache the right-hand value.
value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ false, location);
@@ -147,6 +148,19 @@ namespace ts {
return false;
}
function bindingOrAssignmentElementContainsNonLiteralComputedName(element: BindingOrAssignmentElement): boolean {
const propertyName = tryGetPropertyNameOfBindingOrAssignmentElement(element);
if (propertyName && isComputedPropertyName(propertyName) && !isLiteralExpression(propertyName.expression)) {
return true;
}
const target = getTargetOfBindingOrAssignmentElement(element);
return !!target && isBindingOrAssignmentPattern(target) && bindingOrAssignmentPatternContainsNonLiteralComputedName(target);
}
function bindingOrAssignmentPatternContainsNonLiteralComputedName(pattern: BindingOrAssignmentPattern): boolean {
return !!forEach(getElementsOfBindingOrAssignmentPattern(pattern), bindingOrAssignmentElementContainsNonLiteralComputedName);
}
/**
* Flattens a VariableDeclaration or ParameterDeclaration to one or more variable declarations.
*
@@ -184,7 +198,8 @@ namespace ts {
if (isVariableDeclaration(node)) {
let initializer = getInitializerOfBindingOrAssignmentElement(node);
if (initializer && isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText)) {
if (initializer && (isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText) ||
bindingOrAssignmentElementContainsNonLiteralComputedName(node))) {
// If the right-hand value of the assignment is also an assignment target then
// we need to cache the right-hand value.
initializer = ensureIdentifier(flattenContext, initializer, /*reuseIdentifierExpressions*/ false, initializer);