@@ -819,6 +819,7 @@ namespace ts {
819
819
let flowLoopCount = 0;
820
820
let sharedFlowCount = 0;
821
821
let flowAnalysisDisabled = false;
822
+ let flowInvocationCount = 0;
822
823
823
824
const emptyStringType = getLiteralType("");
824
825
const zeroType = getLiteralType(0);
@@ -834,8 +835,7 @@ namespace ts {
834
835
const symbolLinks: SymbolLinks[] = [];
835
836
const nodeLinks: NodeLinks[] = [];
836
837
const flowLoopCaches: Map<Type>[] = [];
837
- const flowAssignmentKeys: string[] = [];
838
- const flowAssignmentTypes: FlowType[] = [];
838
+ const flowAssignmentTypes: Type[] = [];
839
839
const flowLoopNodes: FlowNode[] = [];
840
840
const flowLoopKeys: string[] = [];
841
841
const flowLoopTypes: Type[][] = [];
@@ -16698,12 +16698,6 @@ namespace ts {
16698
16698
getInitialTypeOfBindingElement(node);
16699
16699
}
16700
16700
16701
- function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression, reference: Node) {
16702
- return getConstraintForLocation(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
16703
- getInitialType(<VariableDeclaration | BindingElement>node) :
16704
- getAssignedType(node), reference);
16705
- }
16706
-
16707
16701
function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) {
16708
16702
return node.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>node).initializer &&
16709
16703
isEmptyArrayLiteral((<VariableDeclaration>node).initializer!) ||
@@ -16990,6 +16984,7 @@ namespace ts {
16990
16984
if (!reference.flowNode || !couldBeUninitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
16991
16985
return declaredType;
16992
16986
}
16987
+ flowInvocationCount++;
16993
16988
const sharedFlowStart = sharedFlowCount;
16994
16989
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
16995
16990
sharedFlowCount = sharedFlowStart;
@@ -17022,15 +17017,6 @@ namespace ts {
17022
17017
flowDepth++;
17023
17018
while (true) {
17024
17019
const flags = flow.flags;
17025
- if (flags & FlowFlags.Cached) {
17026
- const key = getOrSetCacheKey();
17027
- if (key) {
17028
- const id = getFlowNodeId(flow);
17029
- if (flowAssignmentKeys[id] === key) {
17030
- return flowAssignmentTypes[id];
17031
- }
17032
- }
17033
- }
17034
17020
if (flags & FlowFlags.Shared) {
17035
17021
// We cache results of flow type resolution for shared nodes that were previously visited in
17036
17022
// the same getFlowTypeOfReference invocation. A node is considered shared when it is the
@@ -17061,15 +17047,6 @@ namespace ts {
17061
17047
flow = (<FlowAssignment>flow).antecedent;
17062
17048
continue;
17063
17049
}
17064
- else if (flowLoopCount === flowLoopStart) { // Only cache assignments when not within loop analysis
17065
- const key = getOrSetCacheKey();
17066
- if (key && !isIncomplete(type)) {
17067
- flow.flags |= FlowFlags.Cached;
17068
- const id = getFlowNodeId(flow);
17069
- flowAssignmentKeys[id] = key;
17070
- flowAssignmentTypes[id] = type;
17071
- }
17072
- }
17073
17050
}
17074
17051
else if (flags & FlowFlags.Condition) {
17075
17052
type = getTypeAtFlowCondition(<FlowCondition>flow);
@@ -17122,6 +17099,27 @@ namespace ts {
17122
17099
}
17123
17100
}
17124
17101
17102
+ function getInitialOrAssignedType(flow: FlowAssignment, reference: Node) {
17103
+ const node = flow.node;
17104
+ if (flow.flags & FlowFlags.Cached) {
17105
+ const cached = flowAssignmentTypes[getNodeId(node)];
17106
+ if (cached) {
17107
+ return cached;
17108
+ }
17109
+ }
17110
+ const startInvocationCount = flowInvocationCount;
17111
+ const type = getConstraintForLocation(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
17112
+ getInitialType(<VariableDeclaration | BindingElement>node) :
17113
+ getAssignedType(node), reference);
17114
+ // We cache the assigned type when getFlowTypeOfReference was recursively invoked in the
17115
+ // resolution of the assigned type and we're not within loop analysis.
17116
+ if (flowInvocationCount !== startInvocationCount && flowLoopCount === flowLoopStart) {
17117
+ flow.flags |= FlowFlags.Cached;
17118
+ flowAssignmentTypes[getNodeId(node)] = type;
17119
+ }
17120
+ return type;
17121
+ }
17122
+
17125
17123
function getTypeAtFlowAssignment(flow: FlowAssignment) {
17126
17124
const node = flow.node;
17127
17125
// Assignments only narrow the computed type if the declared type is a union type. Thus, we
@@ -17135,11 +17133,11 @@ namespace ts {
17135
17133
if (isEmptyArrayAssignment(node)) {
17136
17134
return getEvolvingArrayType(neverType);
17137
17135
}
17138
- const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(node , reference));
17136
+ const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(flow , reference));
17139
17137
return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType;
17140
17138
}
17141
17139
if (declaredType.flags & TypeFlags.Union) {
17142
- return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node , reference));
17140
+ return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(flow , reference));
17143
17141
}
17144
17142
return declaredType;
17145
17143
}
0 commit comments