Skip to content

Commit 99ab53e

Browse files
committed
Make flow nodes more monomorphic
1 parent df02ad6 commit 99ab53e

File tree

3 files changed

+50
-33
lines changed

3 files changed

+50
-33
lines changed

src/compiler/binder.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ namespace ts {
148148
let Symbol: new (flags: SymbolFlags, name: __String) => Symbol; // tslint:disable-line variable-name
149149
let classifiableNames: UnderscoreEscapedMap<true>;
150150

151-
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
152-
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
151+
const unreachableFlow = createFlowNode(FlowFlags.Unreachable, /*antecedent*/ undefined, /*node*/ undefined);
152+
const reportedUnreachableFlow: FlowNode = createFlowNode(FlowFlags.Unreachable, /*antecedent*/ undefined, /*node*/ undefined);
153153

154154
// state used to aggregate transform flags during bind.
155155
let subtreeTransformFlags: TransformFlags = TransformFlags.None;
@@ -560,9 +560,9 @@ namespace ts {
560560
// A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
561561
// similarly to break statements that exit to a label just past the statement body.
562562
if (!isIIFE) {
563-
currentFlow = { flags: FlowFlags.Start };
563+
currentFlow = createFlowNode(FlowFlags.Start, /*antecedent*/ undefined, /*node*/ undefined) as FlowStart;
564564
if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethod)) {
565-
currentFlow.container = <FunctionExpression | ArrowFunction | MethodDeclaration>node;
565+
currentFlow.node = <FunctionExpression | ArrowFunction | MethodDeclaration>node;
566566
}
567567
}
568568
// We create a return control flow graph for IIFEs and constructors. For constructors
@@ -842,18 +842,22 @@ namespace ts {
842842
return isNarrowableReference(expr);
843843
}
844844

845-
function createBranchLabel(): FlowLabel {
845+
function createFlowNode(flags: FlowFlags, antecedent: FlowNode | undefined, node: Node | undefined) {
846846
return {
847-
flags: FlowFlags.BranchLabel,
848-
antecedents: undefined
849-
};
847+
flags,
848+
antecedent,
849+
node,
850+
id: undefined,
851+
antecedents: undefined,
852+
} as FlowNode;
853+
}
854+
855+
function createBranchLabel(): FlowLabel {
856+
return createFlowNode(FlowFlags.BranchLabel, /*antecedent*/ undefined, /*node*/ undefined) as FlowLabel;
850857
}
851858

852859
function createLoopLabel(): FlowLabel {
853-
return {
854-
flags: FlowFlags.LoopLabel,
855-
antecedents: undefined
856-
};
860+
return createFlowNode(FlowFlags.LoopLabel, /*antecedent*/ undefined, /*node*/ undefined) as FlowLabel;
857861
}
858862

859863
function setFlowNodeReferenced(flow: FlowNode) {
@@ -883,31 +887,34 @@ namespace ts {
883887
return antecedent;
884888
}
885889
setFlowNodeReferenced(antecedent);
886-
return flowNodeCreated({ flags, expression, antecedent });
890+
return flowNodeCreated(createFlowNode(flags, antecedent, expression));
887891
}
888892

889893
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
890894
if (!isNarrowingExpression(switchStatement.expression)) {
891895
return antecedent;
892896
}
893897
setFlowNodeReferenced(antecedent);
894-
return flowNodeCreated({ flags: FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent });
898+
const result = createFlowNode(FlowFlags.SwitchClause, antecedent, /*node*/ undefined) as FlowSwitchClause;
899+
result.switchStatement = switchStatement;
900+
result.clauseStart = clauseStart;
901+
result.clauseEnd = clauseEnd;
902+
return flowNodeCreated(result);
895903
}
896904

897905
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
898906
setFlowNodeReferenced(antecedent);
899-
return flowNodeCreated({ flags: FlowFlags.Assignment, antecedent, node });
907+
return flowNodeCreated(createFlowNode(FlowFlags.Assignment, antecedent, node));
900908
}
901909

902910
function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode {
903911
setFlowNodeReferenced(antecedent);
904-
return flowNodeCreated({ flags: FlowFlags.Call, antecedent, node });
912+
return flowNodeCreated(createFlowNode(FlowFlags.Call, antecedent, node));
905913
}
906914

907915
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
908916
setFlowNodeReferenced(antecedent);
909-
const res: FlowArrayMutation = flowNodeCreated({ flags: FlowFlags.ArrayMutation, antecedent, node });
910-
return res;
917+
return flowNodeCreated(createFlowNode(FlowFlags.ArrayMutation, antecedent, node));
911918
}
912919

913920
function finishFlowLabel(flow: FlowLabel): FlowNode {
@@ -1185,7 +1192,8 @@ namespace ts {
11851192
//
11861193
// extra edges that we inject allows to control this behavior
11871194
// 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.
1188-
const preFinallyFlow: PreFinallyFlow = { flags: FlowFlags.PreFinally, antecedent: preFinallyPrior, lock: {} };
1195+
const preFinallyFlow = createFlowNode(FlowFlags.PreFinally, preFinallyPrior, /*node*/ undefined) as PreFinallyFlow;
1196+
preFinallyFlow.lock = {};
11891197
addAntecedent(preFinallyLabel, preFinallyFlow);
11901198

11911199
currentFlow = finishFlowLabel(preFinallyLabel);
@@ -1204,7 +1212,7 @@ namespace ts {
12041212
}
12051213
}
12061214
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
1207-
const afterFinallyFlow: AfterFinallyFlow = flowNodeCreated({ flags: FlowFlags.AfterFinally, antecedent: currentFlow });
1215+
const afterFinallyFlow = flowNodeCreated(createFlowNode(FlowFlags.AfterFinally, currentFlow, /*node*/ undefined) as AfterFinallyFlow);
12081216
preFinallyFlow.lock = afterFinallyFlow;
12091217
currentFlow = afterFinallyFlow;
12101218
}
@@ -1828,7 +1836,7 @@ namespace ts {
18281836
const host = getJSDocHost(typeAlias);
18291837
container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file;
18301838
blockScopeContainer = getEnclosingBlockScopeContainer(host) || file;
1831-
currentFlow = { flags: FlowFlags.Start };
1839+
currentFlow = createFlowNode(FlowFlags.Start, /*antecedent*/ undefined, /*node*/ undefined);
18321840
parent = typeAlias;
18331841
bind(typeAlias.typeExpression);
18341842
if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) {

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17001,7 +17001,7 @@ namespace ts {
1700117001
}
1700217002
else if (flags & FlowFlags.Start) {
1700317003
// Check if we should continue with the control flow of the containing function.
17004-
const container = (<FlowStart>flow).container;
17004+
const container = (<FlowStart>flow).node;
1700517005
if (container && container !== flowContainer &&
1700617006
reference.kind !== SyntaxKind.PropertyAccessExpression &&
1700717007
reference.kind !== SyntaxKind.ElementAccessExpression &&
@@ -17150,7 +17150,7 @@ namespace ts {
1715017150
// *only* place a silent never type is ever generated.
1715117151
const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
1715217152
const nonEvolvingType = finalizeEvolvingArrayType(type);
17153-
const narrowedType = narrowType(nonEvolvingType, flow.expression, assumeTrue);
17153+
const narrowedType = narrowType(nonEvolvingType, flow.node, assumeTrue);
1715417154
if (narrowedType === nonEvolvingType) {
1715517155
return flowType;
1715617156
}

src/compiler/types.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,6 +2565,22 @@ namespace ts {
25652565
Condition = TrueCondition | FalseCondition
25662566
}
25672567

2568+
export type FlowNode =
2569+
| AfterFinallyFlow
2570+
| PreFinallyFlow
2571+
| FlowStart
2572+
| FlowLabel
2573+
| FlowAssignment
2574+
| FlowCall
2575+
| FlowCondition
2576+
| FlowSwitchClause
2577+
| FlowArrayMutation;
2578+
2579+
export interface FlowNodeBase {
2580+
flags: FlowFlags;
2581+
id: number | undefined; // Node id used by flow type cache in checker
2582+
}
2583+
25682584
export interface FlowLock {
25692585
locked?: boolean;
25702586
}
@@ -2578,18 +2594,11 @@ namespace ts {
25782594
lock: FlowLock;
25792595
}
25802596

2581-
export type FlowNode =
2582-
| AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation;
2583-
export interface FlowNodeBase {
2584-
flags: FlowFlags;
2585-
id?: number; // Node id used by flow type cache in checker
2586-
}
2587-
25882597
// FlowStart represents the start of a control flow. For a function expression or arrow
2589-
// function, the container property references the function (which in turn has a flowNode
2598+
// function, the node property references the function (which in turn has a flowNode
25902599
// property for the containing control flow).
25912600
export interface FlowStart extends FlowNodeBase {
2592-
container?: FunctionExpression | ArrowFunction | MethodDeclaration;
2601+
node?: FunctionExpression | ArrowFunction | MethodDeclaration;
25932602
}
25942603

25952604
// FlowLabel represents a junction with multiple possible preceding control flows.
@@ -2612,7 +2621,7 @@ namespace ts {
26122621
// FlowCondition represents a condition that is known to be true or false at the
26132622
// node's location in the control flow.
26142623
export interface FlowCondition extends FlowNodeBase {
2615-
expression: Expression;
2624+
node: Expression;
26162625
antecedent: FlowNode;
26172626
}
26182627

0 commit comments

Comments
 (0)