From 1dedca73d120e396fa710c782d2a3bf59252d732 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 13 Oct 2016 09:43:55 -0700 Subject: [PATCH] Support 'unshift' and fix typo --- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 18 ++++++++++-------- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 4 ++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6926403d9bb..65d620f9233 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1217,7 +1217,7 @@ namespace ts { } if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { const propertyAccess = node.expression; - if (isNarrowableOperand(propertyAccess.expression) && propertyAccess.name.text === "push") { + if (isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) { currentFlow = createFlowArrayMutation(currentFlow, node); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9e2b7a31748..7bec343c91e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8405,8 +8405,10 @@ namespace ts { } function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) { - return node.kind === SyntaxKind.VariableDeclaration && (node).initializer && isEmptyArrayLiteral((node).initializer) || - node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression && isEmptyArrayLiteral((node.parent).right); + return node.kind === SyntaxKind.VariableDeclaration && (node).initializer && + isEmptyArrayLiteral((node).initializer) || + node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression && + isEmptyArrayLiteral((node.parent).right); } function getReferenceCandidate(node: Expression): Expression { @@ -8562,12 +8564,12 @@ namespace ts { getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction); } - // Return true if the given node is 'x' in an 'x.push(value)' operation. - function isPushCallTarget(node: Node) { + // Return true if the given node is 'x' in an 'x.push(value)' or 'x.unshift(value)' operation. + function isPushOrUnshiftCallTarget(node: Node) { const parent = getReferenceRoot(node).parent; return parent.kind === SyntaxKind.PropertyAccessExpression && - (parent).name.text === "push" && - parent.parent.kind === SyntaxKind.CallExpression; + parent.parent.kind === SyntaxKind.CallExpression && + isPushOrUnshiftIdentifier((parent).name); } // Return true if the given node is 'x' in an 'x[n] = value' operation, where 'n' is an @@ -8596,9 +8598,9 @@ namespace ts { const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode)); visitedFlowCount = visitedFlowStart; // When the reference is 'x' in an 'x.push(value)' or 'x[n] = value' operation, we give type - // 'any[]' to 'x' instead of using the type determed by control flow analysis such that new + // 'any[]' to 'x' instead of using the type determined by control flow analysis such that new // element types are not considered errors. - const isEvolvingArrayInferenceTarget = isEvolvingArrayType(evolvedType) && (isPushCallTarget(reference) || isElementAssignmentTarget(reference)); + const isEvolvingArrayInferenceTarget = isEvolvingArrayType(evolvedType) && (isPushOrUnshiftCallTarget(reference) || isElementAssignmentTarget(reference)); const resultType = isEvolvingArrayInferenceTarget ? anyArrayType : finalizeEvolvingArrayType(evolvedType); if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) { return declaredType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5c32649d97c..ff7618c8e37 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1953,7 +1953,7 @@ namespace ts { } // FlowArrayMutation represents a node potentially mutates an array, i.e. an - // operation of the form 'x.push(value)' or 'x[n] = value'. + // operation of the form 'x.push(value)', 'x.unshift(value)' or 'x[n] = value'. export interface FlowArrayMutation extends FlowNode { node: CallExpression | BinaryExpression; antecedent: FlowNode; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 558015bb0e3..6e7dd8702f7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1895,6 +1895,10 @@ namespace ts { return node.kind === SyntaxKind.Identifier && (node).text === "Symbol"; } + export function isPushOrUnshiftIdentifier(node: Identifier) { + return node.text === "push" || node.text === "unshift"; + } + export function isModifierKind(token: SyntaxKind): boolean { switch (token) { case SyntaxKind.AbstractKeyword: