Skip to content

Commit e6b588a

Browse files
committed
Support parentheses and comma operator with evolving arrays
1 parent 89826a5 commit e6b588a

File tree

3 files changed

+30
-16
lines changed

3 files changed

+30
-16
lines changed

src/compiler/binder.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ namespace ts {
760760
};
761761
}
762762

763-
function createFlowArrayMutation(antecedent: FlowNode, node: Expression): FlowNode {
763+
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
764764
setFlowNodeReferenced(antecedent);
765765
return <FlowArrayMutation>{
766766
flags: FlowFlags.ArrayMutation,
@@ -1151,8 +1151,8 @@ namespace ts {
11511151
bindAssignmentTargetFlow(node.left);
11521152
if (node.left.kind === SyntaxKind.ElementAccessExpression) {
11531153
const elementAccess = <ElementAccessExpression>node.left;
1154-
if (isNarrowableReference(elementAccess.expression)) {
1155-
currentFlow = createFlowArrayMutation(currentFlow, elementAccess.expression);
1154+
if (isNarrowableOperand(elementAccess.expression)) {
1155+
currentFlow = createFlowArrayMutation(currentFlow, node);
11561156
}
11571157
}
11581158
}
@@ -1217,8 +1217,8 @@ namespace ts {
12171217
}
12181218
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
12191219
const propertyAccess = <PropertyAccessExpression>node.expression;
1220-
if (isNarrowableReference(propertyAccess.expression) && propertyAccess.name.text === "push") {
1221-
currentFlow = createFlowArrayMutation(currentFlow, propertyAccess.expression);
1220+
if (isNarrowableOperand(propertyAccess.expression) && propertyAccess.name.text === "push") {
1221+
currentFlow = createFlowArrayMutation(currentFlow, node);
12221222
}
12231223
}
12241224
}

src/compiler/checker.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8424,6 +8424,14 @@ namespace ts {
84248424
return node;
84258425
}
84268426

8427+
function getReferenceParent(node: Node): Node {
8428+
const parent = node.parent;
8429+
return parent.kind === SyntaxKind.ParenthesizedExpression ||
8430+
parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken && (<BinaryExpression>parent).left === node ||
8431+
parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.CommaToken && (<BinaryExpression>parent).right === node ?
8432+
getReferenceParent(parent) : parent;
8433+
}
8434+
84278435
function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) {
84288436
if (clause.kind === SyntaxKind.CaseClause) {
84298437
const caseType = getRegularTypeOfLiteralType(checkExpression((<CaseClause>clause).expression));
@@ -8556,15 +8564,16 @@ namespace ts {
85568564

85578565
// Return true if the given node is 'x' in an 'x.push(value)' operation.
85588566
function isPushCallTarget(node: Node) {
8559-
return node.parent.kind === SyntaxKind.PropertyAccessExpression &&
8560-
(<PropertyAccessExpression>node.parent).name.text === "push" &&
8561-
node.parent.parent.kind === SyntaxKind.CallExpression;
8567+
const parent = getReferenceParent(node);
8568+
return parent.kind === SyntaxKind.PropertyAccessExpression &&
8569+
(<PropertyAccessExpression>parent).name.text === "push" &&
8570+
parent.parent.kind === SyntaxKind.CallExpression;
85628571
}
85638572

85648573
// Return true if the given node is 'x' in an 'x[n] = value' operation, where 'n' is an
85658574
// expression of type any, undefined, or a number-like type.
85668575
function isElementAssignmentTarget(node: Node) {
8567-
const parent = node.parent;
8576+
const parent = getReferenceParent(node);
85688577
return parent.kind === SyntaxKind.ElementAccessExpression &&
85698578
(<ElementAccessExpression>parent).expression === node &&
85708579
parent.parent.kind === SyntaxKind.BinaryExpression &&
@@ -8696,19 +8705,24 @@ namespace ts {
86968705

86978706
function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType {
86988707
const node = flow.node;
8699-
if (isMatchingReference(reference, node)) {
8708+
const expr = node.kind === SyntaxKind.CallExpression ?
8709+
(<PropertyAccessExpression>(<CallExpression>node).expression).expression :
8710+
(<ElementAccessExpression>(<BinaryExpression>node).left).expression;
8711+
if (isMatchingReference(reference, getReferenceCandidate(expr))) {
87008712
const flowType = getTypeAtFlowNode(flow.antecedent);
87018713
const type = getTypeFromFlowType(flowType);
87028714
if (isEvolvingArrayType(type)) {
8703-
const parent = node.parent;
87048715
let evolvedType = <AnonymousType>type;
8705-
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
8706-
for (const arg of (<CallExpression>parent.parent).arguments) {
8716+
if (node.kind === SyntaxKind.CallExpression) {
8717+
for (const arg of (<CallExpression>node).arguments) {
87078718
evolvedType = addEvolvingArrayElementType(evolvedType, arg);
87088719
}
87098720
}
8710-
else if (isTypeAnyOrAllConstituentTypesHaveKind(checkExpression((<ElementAccessExpression>parent).argumentExpression), TypeFlags.NumberLike)) {
8711-
evolvedType = addEvolvingArrayElementType(evolvedType, (<BinaryExpression>parent.parent).right);
8721+
else {
8722+
const indexType = checkExpression((<ElementAccessExpression>(<BinaryExpression>node).left).argumentExpression);
8723+
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike | TypeFlags.Undefined)) {
8724+
evolvedType = addEvolvingArrayElementType(evolvedType, (<BinaryExpression>node).right);
8725+
}
87128726
}
87138727
return evolvedType === type ? flowType : createFlowType(evolvedType, isIncomplete(flowType));
87148728
}

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1955,7 +1955,7 @@ namespace ts {
19551955
// FlowArrayMutation represents a node potentially mutates an array, i.e. an
19561956
// operation of the form 'x.push(value)' or 'x[n] = value'.
19571957
export interface FlowArrayMutation extends FlowNode {
1958-
node: Expression;
1958+
node: CallExpression | BinaryExpression;
19591959
antecedent: FlowNode;
19601960
}
19611961

0 commit comments

Comments
 (0)