Skip to content

Commit 1e47834

Browse files
committed
Binder factory experiment
1 parent 00dc0b6 commit 1e47834

File tree

3 files changed

+107
-14
lines changed

3 files changed

+107
-14
lines changed

src/compiler/binder.ts

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,17 @@ import {
6262
Expression,
6363
ExpressionStatement,
6464
findAncestor,
65+
FlowArrayMutation,
66+
FlowAssignment,
67+
FlowCall,
68+
FlowCondition,
6569
FlowFlags,
6670
FlowLabel,
6771
FlowNode,
72+
FlowNodeBase,
6873
FlowReduceLabel,
74+
FlowStart,
75+
FlowSwitchClause,
6976
forEach,
7077
forEachChild,
7178
ForInOrOfStatement,
@@ -464,11 +471,88 @@ const enum ContainerFlags {
464471
IsObjectLiteralOrClassExpressionMethodOrAccessor = 1 << 7,
465472
}
466473

467-
function initFlowNode<T extends FlowNode>(node: T) {
468-
Debug.attachFlowNodeDebugInfo(node);
469-
return node;
474+
function createFlowNode<T extends FlowNode>(
475+
flags: FlowFlags,
476+
node?: Node,
477+
antecedent?: FlowNode,
478+
antecedents?: FlowNode[],
479+
target?: FlowLabel,
480+
switchStatement?: SwitchStatement,
481+
clauseStart?: number,
482+
clauseEnd?: number,
483+
): T {
484+
// Create all flow nodes in a predictable order. If FlowNode changes, add more
485+
// properties here.
486+
const flowNode: FlowNodeBase = {
487+
flags,
488+
id: undefined,
489+
node,
490+
antecedent,
491+
antecedents,
492+
target,
493+
switchStatement,
494+
clauseStart,
495+
clauseEnd,
496+
};
497+
Debug.attachFlowNodeDebugInfo(flowNode);
498+
return flowNode as T;
470499
}
471500

501+
function createFlowStartNode(flags: FlowFlags): FlowStart {
502+
return createFlowNode(flags);
503+
}
504+
505+
function createFlowLabelNode(
506+
flags: FlowFlags,
507+
antecedents: FlowNode[] | undefined,
508+
): FlowLabel {
509+
return createFlowNode(flags, /*node*/ undefined, /*antecedent*/ undefined, antecedents);
510+
}
511+
512+
function createFlowMutationNode(
513+
flags: FlowFlags,
514+
node: FlowAssignment["node"] | FlowArrayMutation["node"],
515+
antecedent: FlowNode,
516+
): FlowAssignment | FlowArrayMutation {
517+
return createFlowNode(flags, node, antecedent);
518+
}
519+
520+
function createFlowConditionNode(
521+
flags: FlowFlags,
522+
node: FlowCondition["node"],
523+
antecedent: FlowNode,
524+
): FlowCondition {
525+
return createFlowNode(flags, node, antecedent);
526+
}
527+
528+
function createFlowSwitchClauseNode(
529+
flags: FlowFlags,
530+
switchStatement: SwitchStatement,
531+
clauseStart: number,
532+
clauseEnd: number,
533+
antecedent: FlowNode,
534+
): FlowSwitchClause {
535+
return createFlowNode(flags, /*node*/ undefined, antecedent, /*antecedents*/ undefined, /*target*/ undefined, switchStatement, clauseStart, clauseEnd);
536+
}
537+
538+
function createFlowCallNode(
539+
flags: FlowFlags,
540+
node: FlowCall["node"],
541+
antecedent: FlowNode,
542+
): FlowCall {
543+
return createFlowNode(flags, node, antecedent);
544+
}
545+
546+
function createFlowReduceLabelNode(
547+
flags: FlowFlags,
548+
antecedent: FlowNode,
549+
antecedents: FlowNode[],
550+
target: FlowLabel,
551+
): FlowReduceLabel {
552+
return createFlowNode(flags, /*node*/ undefined, antecedent, antecedents, target);
553+
}
554+
555+
472556
const binder = createBinder();
473557

474558
/** @internal */
@@ -965,7 +1049,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
9651049
// A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
9661050
// similarly to break statements that exit to a label just past the statement body.
9671051
if (!isImmediatelyInvoked) {
968-
currentFlow = initFlowNode({ flags: FlowFlags.Start });
1052+
currentFlow = createFlowStartNode(FlowFlags.Start);
9691053
if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor)) {
9701054
currentFlow.node = node as FunctionExpression | ArrowFunction | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration;
9711055
}
@@ -1261,15 +1345,15 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
12611345
}
12621346

12631347
function createBranchLabel(): FlowLabel {
1264-
return initFlowNode({ flags: FlowFlags.BranchLabel, antecedents: undefined });
1348+
return createFlowLabelNode(FlowFlags.BranchLabel, /*antecedents*/ undefined);
12651349
}
12661350

12671351
function createLoopLabel(): FlowLabel {
1268-
return initFlowNode({ flags: FlowFlags.LoopLabel, antecedents: undefined });
1352+
return createFlowLabelNode(FlowFlags.LoopLabel, /*antecedents*/ undefined);
12691353
}
12701354

12711355
function createReduceLabel(target: FlowLabel, antecedents: FlowNode[], antecedent: FlowNode): FlowReduceLabel {
1272-
return initFlowNode({ flags: FlowFlags.ReduceLabel, target, antecedents, antecedent });
1356+
return createFlowReduceLabelNode(FlowFlags.ReduceLabel, antecedent, antecedents, target);
12731357
}
12741358

12751359
function setFlowNodeReferenced(flow: FlowNode) {
@@ -1300,17 +1384,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13001384
return antecedent;
13011385
}
13021386
setFlowNodeReferenced(antecedent);
1303-
return initFlowNode({ flags, antecedent, node: expression });
1387+
return createFlowConditionNode(flags, expression, antecedent);
13041388
}
13051389

13061390
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
13071391
setFlowNodeReferenced(antecedent);
1308-
return initFlowNode({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd });
1392+
return createFlowSwitchClauseNode(FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent);
13091393
}
13101394

13111395
function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Expression | VariableDeclaration | ArrayBindingElement): FlowNode {
13121396
setFlowNodeReferenced(antecedent);
1313-
const result = initFlowNode({ flags, antecedent, node });
1397+
const result = createFlowMutationNode(flags, node, antecedent);
13141398
if (currentExceptionTarget) {
13151399
addAntecedent(currentExceptionTarget, result);
13161400
}
@@ -1319,7 +1403,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13191403

13201404
function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode {
13211405
setFlowNodeReferenced(antecedent);
1322-
return initFlowNode({ flags: FlowFlags.Call, antecedent, node });
1406+
return createFlowCallNode(FlowFlags.Call, node, antecedent);
13231407
}
13241408

13251409
function finishFlowLabel(flow: FlowLabel): FlowNode {
@@ -2415,7 +2499,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
24152499
const host = typeAlias.parent.parent;
24162500
container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file;
24172501
blockScopeContainer = getEnclosingBlockScopeContainer(host) || file;
2418-
currentFlow = initFlowNode({ flags: FlowFlags.Start });
2502+
currentFlow = createFlowStartNode(FlowFlags.Start);
24192503
parent = typeAlias;
24202504
bind(typeAlias.typeExpression);
24212505
const declName = getNameOfDeclaration(typeAlias);

src/compiler/debug.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ export namespace Debug {
519519
}
520520
},
521521
__debugFlowFlags: { get(this: FlowNodeBase) { return formatEnum(this.flags, (ts as any).FlowFlags, /*isFlags*/ true); } },
522-
__debugToString: { value(this: FlowNodeBase) { return formatControlFlowGraph(this); } }
522+
__debugToString: { value(this: FlowNodeBase) { return formatControlFlowGraph(this as FlowNode); } }
523523
});
524524
}
525525
}
@@ -912,7 +912,7 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
912912
return !!(f.flags & hasAntecedentFlags);
913913
}
914914

915-
function hasNode(f: FlowNode): f is Extract<FlowNode, { node?: Node }> {
915+
function hasNode(f: FlowNode): f is Extract<FlowNode, { node: Node | undefined }> {
916916
return !!(f.flags & hasNodeFlags);
917917
}
918918

src/compiler/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,6 +3889,15 @@ export type FlowNode =
38893889
export interface FlowNodeBase {
38903890
flags: FlowFlags;
38913891
id?: number; // Node id used by flow type cache in checker
3892+
3893+
// Declared here so we can construct flow nodes with properties in a consistent order.
3894+
/** @internal */ node?: Node;
3895+
/** @internal */ antecedent?: FlowNode;
3896+
/** @internal */ antecedents?: FlowNode[];
3897+
/** @internal */ target?: FlowLabel;
3898+
/** @internal */ switchStatement?: SwitchStatement;
3899+
/** @internal */ clauseStart?: number;
3900+
/** @internal */ clauseEnd?: number;
38923901
}
38933902

38943903
// FlowStart represents the start of a control flow. For a function expression or arrow

0 commit comments

Comments
 (0)