Skip to content

Commit 96a91c9

Browse files
committed
improve control-flow debug output
1 parent 7463860 commit 96a91c9

File tree

6 files changed

+374
-202
lines changed

6 files changed

+374
-202
lines changed

src/compiler/binder.ts

+55-14
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,11 @@ namespace ts {
209209
let symbolCount = 0;
210210

211211
let Symbol: new (flags: SymbolFlags, name: __String) => Symbol;
212+
let FlowNode: new (flags: FlowFlags) => FlowNodeBase;
212213
let classifiableNames: UnderscoreEscapedMap<true>;
213214

214-
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
215-
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
215+
let unreachableFlow: FlowNode;
216+
let reportedUnreachableFlow: FlowNode;
216217

217218
// state used to aggregate transform flags during bind.
218219
let subtreeTransformFlags: TransformFlags = TransformFlags.None;
@@ -227,6 +228,17 @@ namespace ts {
227228
return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, arg0, arg1, arg2);
228229
}
229230

231+
function initializeBinder() {
232+
const symbolConstructor = objectAllocator.getSymbolConstructor();
233+
const flowNodeConstructor = objectAllocator.getFlowNodeConstructor();
234+
if (Symbol !== symbolConstructor || FlowNode !== flowNodeConstructor) {
235+
Symbol = symbolConstructor;
236+
FlowNode = flowNodeConstructor;
237+
unreachableFlow = new FlowNode(FlowFlags.Unreachable);
238+
reportedUnreachableFlow = new FlowNode(FlowFlags.Unreachable);
239+
}
240+
}
241+
230242
function bindSourceFile(f: SourceFile, opts: CompilerOptions) {
231243
file = f;
232244
options = opts;
@@ -236,7 +248,7 @@ namespace ts {
236248
symbolCount = 0;
237249
skipTransformFlagAggregation = file.isDeclarationFile;
238250

239-
Symbol = objectAllocator.getSymbolConstructor();
251+
initializeBinder();
240252

241253
if (!file.locals) {
242254
bind(file);
@@ -623,7 +635,7 @@ namespace ts {
623635
// A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
624636
// similarly to break statements that exit to a label just past the statement body.
625637
if (!isIIFE) {
626-
currentFlow = { flags: FlowFlags.Start };
638+
currentFlow = createFlowStart();
627639
if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethod)) {
628640
currentFlow.node = <FunctionExpression | ArrowFunction | MethodDeclaration>node;
629641
}
@@ -917,11 +929,15 @@ namespace ts {
917929
}
918930

919931
function createBranchLabel(): FlowLabel {
920-
return { flags: FlowFlags.BranchLabel, antecedents: undefined };
932+
const flow = new FlowNode(FlowFlags.BranchLabel) as FlowLabel;
933+
flow.antecedents = undefined;
934+
return flow;
921935
}
922936

923937
function createLoopLabel(): FlowLabel {
924-
return { flags: FlowFlags.LoopLabel, antecedents: undefined };
938+
const flow = new FlowNode(FlowFlags.LoopLabel) as FlowLabel;
939+
flow.antecedents = undefined;
940+
return flow;
925941
}
926942

927943
function setFlowNodeReferenced(flow: FlowNode) {
@@ -936,6 +952,10 @@ namespace ts {
936952
}
937953
}
938954

955+
function createFlowStart(): FlowStart {
956+
return new FlowNode(FlowFlags.Start) as FlowStart;
957+
}
958+
939959
function createFlowCondition(flags: FlowFlags, antecedent: FlowNode, expression: Expression | undefined): FlowNode {
940960
if (antecedent.flags & FlowFlags.Unreachable) {
941961
return antecedent;
@@ -953,30 +973,47 @@ namespace ts {
953973
return antecedent;
954974
}
955975
setFlowNodeReferenced(antecedent);
956-
return flowNodeCreated({ flags, antecedent, node: expression });
976+
const flow = new FlowNode(flags) as FlowCondition;
977+
flow.antecedent = antecedent;
978+
flow.node = expression;
979+
return flowNodeCreated(flow);
957980
}
958981

959982
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
960983
if (!isNarrowingExpression(switchStatement.expression)) {
961984
return antecedent;
962985
}
963986
setFlowNodeReferenced(antecedent);
964-
return flowNodeCreated({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd });
987+
const flow = new FlowNode(FlowFlags.SwitchClause) as FlowSwitchClause;
988+
flow.antecedent = antecedent;
989+
flow.switchStatement = switchStatement;
990+
flow.clauseStart = clauseStart;
991+
flow.clauseEnd = clauseEnd;
992+
return flowNodeCreated(flow);
965993
}
966994

967995
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
968996
setFlowNodeReferenced(antecedent);
969-
return flowNodeCreated({ flags: FlowFlags.Assignment, antecedent, node });
997+
const flow = new FlowNode(FlowFlags.Assignment) as FlowAssignment;
998+
flow.antecedent = antecedent;
999+
flow.node = node;
1000+
return flowNodeCreated(flow);
9701001
}
9711002

9721003
function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode {
9731004
setFlowNodeReferenced(antecedent);
974-
return flowNodeCreated({ flags: FlowFlags.Call, antecedent, node });
1005+
const flow = new FlowNode(FlowFlags.Call) as FlowCall;
1006+
flow.antecedent = antecedent;
1007+
flow.node = node;
1008+
return flowNodeCreated(flow);
9751009
}
9761010

9771011
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
9781012
setFlowNodeReferenced(antecedent);
979-
return flowNodeCreated({ flags: FlowFlags.ArrayMutation, antecedent, node });
1013+
const flow = new FlowNode(FlowFlags.ArrayMutation) as FlowArrayMutation;
1014+
flow.antecedent = antecedent;
1015+
flow.node = node;
1016+
return flowNodeCreated(flow);
9801017
}
9811018

9821019
function finishFlowLabel(flow: FlowLabel): FlowNode {
@@ -1259,7 +1296,9 @@ namespace ts {
12591296
//
12601297
// extra edges that we inject allows to control this behavior
12611298
// if when walking the flow we step on post-finally edge - we can mark matching pre-finally edge as locked so it will be skipped.
1262-
const preFinallyFlow: PreFinallyFlow = { flags: FlowFlags.PreFinally, antecedent: preFinallyPrior, lock: {} };
1299+
const preFinallyFlow = new FlowNode(FlowFlags.PreFinally) as PreFinallyFlow;
1300+
preFinallyFlow.antecedent = preFinallyPrior;
1301+
preFinallyFlow.lock = {};
12631302
addAntecedent(preFinallyLabel, preFinallyFlow);
12641303

12651304
currentFlow = finishFlowLabel(preFinallyLabel);
@@ -1278,7 +1317,9 @@ namespace ts {
12781317
}
12791318
}
12801319
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
1281-
const afterFinallyFlow: AfterFinallyFlow = flowNodeCreated({ flags: FlowFlags.AfterFinally, antecedent: currentFlow });
1320+
const afterFinallyFlow = new FlowNode(FlowFlags.AfterFinally) as AfterFinallyFlow;
1321+
afterFinallyFlow.antecedent = currentFlow;
1322+
flowNodeCreated(afterFinallyFlow);
12821323
preFinallyFlow.lock = afterFinallyFlow;
12831324
currentFlow = afterFinallyFlow;
12841325
}
@@ -1986,7 +2027,7 @@ namespace ts {
19862027
const host = getJSDocHost(typeAlias);
19872028
container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file;
19882029
blockScopeContainer = getEnclosingBlockScopeContainer(host) || file;
1989-
currentFlow = { flags: FlowFlags.Start };
2030+
currentFlow = createFlowStart();
19902031
parent = typeAlias;
19912032
bind(typeAlias.typeExpression);
19922033
const declName = getNameOfDeclaration(typeAlias);

src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18083,7 +18083,7 @@ namespace ts {
1808318083
}
1808418084

1808518085
function getFlowNodeId(flow: FlowNode): number {
18086-
if (!flow.id) {
18086+
if (!flow.id || flow.id < 0) {
1808718087
flow.id = nextFlowId;
1808818088
nextFlowId++;
1808918089
}

src/compiler/core.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,7 @@ namespace ts {
11591159
}
11601160
}
11611161

1162-
function stableSortIndices<T>(array: readonly T[], indices: number[], comparer: Comparer<T>) {
1162+
export function stableSortIndices<T>(array: readonly T[], indices: number[], comparer: Comparer<T>) {
11631163
// sort indices by value then position
11641164
indices.sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y));
11651165
}

0 commit comments

Comments
 (0)