Skip to content

Commit e97ebb7

Browse files
committed
More efficient scheme for caching flow node reachability
1 parent 05d1e68 commit e97ebb7

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace ts {
66
let nextNodeId = 1;
77
let nextMergeId = 1;
88
let nextFlowId = 1;
9+
let nextCheckerId = 1;
910

1011
const enum IterationUse {
1112
AllowsSyncIterablesFlag = 1 << 0,
@@ -298,6 +299,7 @@ namespace ts {
298299
let instantiationDepth = 0;
299300
let constraintDepth = 0;
300301
let currentNode: Node | undefined;
302+
let checkerId: number;
301303

302304
const emptySymbols = createSymbolTable();
303305
const identityMapper: (type: Type) => Type = identity;
@@ -842,7 +844,6 @@ namespace ts {
842844
const flowLoopTypes: Type[][] = [];
843845
const sharedFlowNodes: FlowNode[] = [];
844846
const sharedFlowTypes: FlowType[] = [];
845-
const flowNodeReachable: (boolean | undefined)[] = [];
846847
const potentialThisCollisions: Node[] = [];
847848
const potentialNewTargetCollisions: Node[] = [];
848849
const awaitedTypeStack: number[] = [];
@@ -16993,17 +16994,21 @@ namespace ts {
1699316994
}
1699416995

1699516996
function isReachableFlowNode(flow: FlowNode) {
16996-
return isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false);
16997+
return isReachableFlowNodeWorker(flow, /*noCacheCheck*/ false);
1699716998
}
1699816999

1699917000
function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean {
1700017001
while (true) {
1700117002
const flags = flow.flags;
17002-
if (flags & FlowFlags.Shared) {
17003+
if (flags & (FlowFlags.Shared | FlowFlags.Assignment | FlowFlags.Label)) {
1700317004
if (!noCacheCheck) {
17004-
const id = getFlowNodeId(flow);
17005-
const reachable = flowNodeReachable[id];
17006-
return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ true));
17005+
if (flow.checkerId === checkerId) {
17006+
return !!(flow.flags & FlowFlags.Reachable);
17007+
}
17008+
const reachable = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true);
17009+
flow.checkerId = checkerId;
17010+
flow.flags = (flow.flags & ~FlowFlags.Reachable) | (reachable ? FlowFlags.Reachable : 0);
17011+
return reachable;
1700717012
}
1700817013
noCacheCheck = false;
1700917014
}
@@ -32287,6 +32292,9 @@ namespace ts {
3228732292
}
3228832293

3228932294
function initializeTypeChecker() {
32295+
checkerId = nextCheckerId;
32296+
nextCheckerId++;
32297+
3229032298
// Bind all source files and propagate errors
3229132299
for (const file of host.getSourceFiles()) {
3229232300
bindSourceFile(file, compilerOptions);

src/compiler/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,8 @@ namespace ts {
25822582
AfterFinally = 1 << 13, // Injected edge that links post-finally flow with the rest of the graph
25832583
/** @internal */
25842584
Cached = 1 << 14, // Indicates that at least one cross-call cache entry exists for this node, even if not a loop participant
2585+
/** @internal */
2586+
Reachable = 1 << 15, // Reachability as computed by isReachableFlowNode
25852587
Label = BranchLabel | LoopLabel,
25862588
Condition = TrueCondition | FalseCondition
25872589
}
@@ -2600,6 +2602,8 @@ namespace ts {
26002602
export interface FlowNodeBase {
26012603
flags: FlowFlags;
26022604
id?: number; // Node id used by flow type cache in checker
2605+
/** @internal */
2606+
checkerId?: number; // Checker id for FlowFlags.Reachable
26032607
}
26042608

26052609
export interface FlowLock {

0 commit comments

Comments
 (0)