Skip to content

Cache flow branch label results the same way as flow loop results #41387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ namespace ts {
const mergedSymbols: Symbol[] = [];
const symbolLinks: SymbolLinks[] = [];
const nodeLinks: NodeLinks[] = [];
const flowLoopCaches: ESMap<string, Type>[] = [];
const flowLabelCaches: ESMap<string, Type>[] = [];
const flowLoopNodes: FlowNode[] = [];
const flowLoopKeys: string[] = [];
const flowLoopTypes: Type[][] = [];
Expand Down Expand Up @@ -21656,6 +21656,7 @@ namespace ts {
let key: string | undefined;
let isKeySet = false;
let flowDepth = 0;
let cacheableBranches = true;
if (flowAnalysisDisabled) {
return errorType;
}
Expand Down Expand Up @@ -21747,9 +21748,14 @@ namespace ts {
else if (flags & FlowFlags.ReduceLabel) {
const target = (<FlowReduceLabel>flow).target;
const saveAntecedents = target.antecedents;
// Modifying the antecedents of a node means we lose our ability to use the cross-invocation branch cache
// (since that may have follow-on effects on analysis returned by other nodes if the results get cached)
const oldCacheableBranches = cacheableBranches;
cacheableBranches = false;
target.antecedents = (<FlowReduceLabel>flow).antecedents;
type = getTypeAtFlowNode((<FlowReduceLabel>flow).antecedent);
target.antecedents = saveAntecedents;
cacheableBranches = oldCacheableBranches;
}
else if (flags & FlowFlags.Start) {
// Check if we should continue with the control flow of the containing function.
Expand Down Expand Up @@ -21955,6 +21961,17 @@ namespace ts {
}

function getTypeAtFlowBranchLabel(flow: FlowLabel): FlowType {
const id = getFlowNodeId(flow);
const cache = flowLabelCaches[id] || (flowLabelCaches[id] = new Map<string, Type>());
const key = getOrSetCacheKey();
if (!key) {
// No cache key is generated when binding patterns are in unnarrowable situations
return declaredType;
}
const cached = cacheableBranches && cache.get(key);
if (cached) {
return cached;
}
const antecedentTypes: Type[] = [];
let subtypeReduction = false;
let seenIncomplete = false;
Expand Down Expand Up @@ -22004,14 +22021,18 @@ namespace ts {
}
}
}
return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
const result = createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
if (!seenIncomplete && cacheableBranches) {
cache.set(key, result as Type);
}
return result;
}

function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType {
// If we have previously computed the control flow type for the reference at
// this flow loop junction, return the cached type.
const id = getFlowNodeId(flow);
const cache = flowLoopCaches[id] || (flowLoopCaches[id] = new Map<string, Type>());
const cache = flowLabelCaches[id] || (flowLabelCaches[id] = new Map<string, Type>());
const key = getOrSetCacheKey();
if (!key) {
// No cache key is generated when binding patterns are in unnarrowable situations
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//// [controlFlowManyCallExpressionStatementsPerf.ts]
function test(x: boolean): boolean { return x; }

let state = true;

if (state) {
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
}

//// [controlFlowManyCallExpressionStatementsPerf.js]
function test(x) { return x; }
var state = true;
if (state) {
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
}
Loading