@@ -819,6 +819,7 @@ namespace ts {
819819 let flowLoopCount = 0;
820820 let sharedFlowCount = 0;
821821 let flowAnalysisDisabled = false;
822+ let flowInvocationCount = 0;
822823
823824 const emptyStringType = getLiteralType("");
824825 const zeroType = getLiteralType(0);
@@ -834,8 +835,7 @@ namespace ts {
834835 const symbolLinks: SymbolLinks[] = [];
835836 const nodeLinks: NodeLinks[] = [];
836837 const flowLoopCaches: Map<Type>[] = [];
837- const flowAssignmentKeys: string[] = [];
838- const flowAssignmentTypes: FlowType[] = [];
838+ const flowAssignmentTypes: Type[] = [];
839839 const flowLoopNodes: FlowNode[] = [];
840840 const flowLoopKeys: string[] = [];
841841 const flowLoopTypes: Type[][] = [];
@@ -16698,12 +16698,6 @@ namespace ts {
1669816698 getInitialTypeOfBindingElement(node);
1669916699 }
1670016700
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-
1670716701 function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) {
1670816702 return node.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>node).initializer &&
1670916703 isEmptyArrayLiteral((<VariableDeclaration>node).initializer!) ||
@@ -16990,6 +16984,7 @@ namespace ts {
1699016984 if (!reference.flowNode || !couldBeUninitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
1699116985 return declaredType;
1699216986 }
16987+ flowInvocationCount++;
1699316988 const sharedFlowStart = sharedFlowCount;
1699416989 const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
1699516990 sharedFlowCount = sharedFlowStart;
@@ -17022,15 +17017,6 @@ namespace ts {
1702217017 flowDepth++;
1702317018 while (true) {
1702417019 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- }
1703417020 if (flags & FlowFlags.Shared) {
1703517021 // We cache results of flow type resolution for shared nodes that were previously visited in
1703617022 // the same getFlowTypeOfReference invocation. A node is considered shared when it is the
@@ -17061,15 +17047,6 @@ namespace ts {
1706117047 flow = (<FlowAssignment>flow).antecedent;
1706217048 continue;
1706317049 }
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- }
1707317050 }
1707417051 else if (flags & FlowFlags.Condition) {
1707517052 type = getTypeAtFlowCondition(<FlowCondition>flow);
@@ -17122,6 +17099,27 @@ namespace ts {
1712217099 }
1712317100 }
1712417101
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+
1712517123 function getTypeAtFlowAssignment(flow: FlowAssignment) {
1712617124 const node = flow.node;
1712717125 // Assignments only narrow the computed type if the declared type is a union type. Thus, we
@@ -17135,11 +17133,11 @@ namespace ts {
1713517133 if (isEmptyArrayAssignment(node)) {
1713617134 return getEvolvingArrayType(neverType);
1713717135 }
17138- const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(node , reference));
17136+ const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(flow , reference));
1713917137 return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType;
1714017138 }
1714117139 if (declaredType.flags & TypeFlags.Union) {
17142- return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node , reference));
17140+ return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(flow , reference));
1714317141 }
1714417142 return declaredType;
1714517143 }
0 commit comments