Skip to content

Commit d4ad0d5

Browse files
committed
Cheaper caching scheme
1 parent 7b77b49 commit d4ad0d5

File tree

1 file changed

+26
-28
lines changed

1 file changed

+26
-28
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)