@@ -65,10 +65,15 @@ import {
6565 Expression ,
6666 ExpressionStatement ,
6767 findAncestor ,
68+ FlowArrayMutation ,
69+ FlowAssignment ,
70+ FlowCall ,
71+ FlowCondition ,
6872 FlowFlags ,
6973 FlowLabel ,
7074 FlowNode ,
7175 FlowReduceLabel ,
76+ FlowSwitchClause ,
7277 forEach ,
7378 forEachChild ,
7479 ForInOrOfStatement ,
@@ -494,9 +499,9 @@ export const enum ContainerFlags {
494499 IsObjectLiteralOrClassExpressionMethodOrAccessor = 1 << 7 ,
495500}
496501
497- function initFlowNode < T extends FlowNode > ( node : T ) {
498- Debug . attachFlowNodeDebugInfo ( node ) ;
499- return node ;
502+ /** @internal */
503+ export function createFlowNode ( flags : FlowFlags , node : unknown , antecedent : FlowNode | FlowNode [ ] | undefined ) : FlowNode {
504+ return Debug . attachFlowNodeDebugInfo ( { flags , id : 0 , node, antecedent } as FlowNode ) ;
500505}
501506
502507const binder = /* @__PURE__ */ createBinder ( ) ;
@@ -557,8 +562,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
557562 var Symbol : new ( flags : SymbolFlags , name : __String ) => Symbol ;
558563 var classifiableNames : Set < __String > ;
559564
560- var unreachableFlow : FlowNode = { flags : FlowFlags . Unreachable } ;
561- var reportedUnreachableFlow : FlowNode = { flags : FlowFlags . Unreachable } ;
565+ var unreachableFlow = createFlowNode ( FlowFlags . Unreachable , /*node*/ undefined , /*antecedent*/ undefined ) ;
566+ var reportedUnreachableFlow = createFlowNode ( FlowFlags . Unreachable , /*node*/ undefined , /*antecedent*/ undefined ) ;
562567 var bindBinaryExpressionFlow = createBindBinaryExpressionFlow ( ) ;
563568 /* eslint-enable no-var */
564569
@@ -1013,7 +1018,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
10131018 // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
10141019 // similarly to break statements that exit to a label just past the statement body.
10151020 if ( ! isImmediatelyInvoked ) {
1016- currentFlow = initFlowNode ( { flags : FlowFlags . Start } ) ;
1021+ currentFlow = createFlowNode ( FlowFlags . Start , /*node*/ undefined , /*antecedent*/ undefined ) ;
10171022 if ( containerFlags & ( ContainerFlags . IsFunctionExpression | ContainerFlags . IsObjectLiteralOrClassExpressionMethodOrAccessor ) ) {
10181023 currentFlow . node = node as FunctionExpression | ArrowFunction | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration ;
10191024 }
@@ -1332,16 +1337,16 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13321337 return containsNarrowableReference ( expr ) ;
13331338 }
13341339
1335- function createBranchLabel ( ) : FlowLabel {
1336- return initFlowNode ( { flags : FlowFlags . BranchLabel , antecedents : undefined } ) ;
1340+ function createBranchLabel ( ) {
1341+ return createFlowNode ( FlowFlags . BranchLabel , /*node*/ undefined , /*antecedent*/ undefined ) as FlowLabel ;
13371342 }
13381343
1339- function createLoopLabel ( ) : FlowLabel {
1340- return initFlowNode ( { flags : FlowFlags . LoopLabel , antecedents : undefined } ) ;
1344+ function createLoopLabel ( ) {
1345+ return createFlowNode ( FlowFlags . LoopLabel , /*node*/ undefined , /*antecedent*/ undefined ) as FlowLabel ;
13411346 }
13421347
1343- function createReduceLabel ( target : FlowLabel , antecedents : FlowNode [ ] , antecedent : FlowNode ) : FlowReduceLabel {
1344- return initFlowNode ( { flags : FlowFlags . ReduceLabel , target, antecedents, antecedent } ) ;
1348+ function createReduceLabel ( target : FlowLabel , antecedents : FlowNode [ ] , antecedent : FlowNode ) {
1349+ return createFlowNode ( FlowFlags . ReduceLabel , { target, antecedents } , antecedent ) as FlowReduceLabel ;
13451350 }
13461351
13471352 function setFlowNodeReferenced ( flow : FlowNode ) {
@@ -1350,13 +1355,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13501355 }
13511356
13521357 function addAntecedent ( label : FlowLabel , antecedent : FlowNode ) : void {
1353- if ( ! ( antecedent . flags & FlowFlags . Unreachable ) && ! contains ( label . antecedents , antecedent ) ) {
1354- ( label . antecedents || ( label . antecedents = [ ] ) ) . push ( antecedent ) ;
1358+ if ( ! ( antecedent . flags & FlowFlags . Unreachable ) && ! contains ( label . antecedent , antecedent ) ) {
1359+ ( label . antecedent || ( label . antecedent = [ ] ) ) . push ( antecedent ) ;
13551360 setFlowNodeReferenced ( antecedent ) ;
13561361 }
13571362 }
13581363
1359- function createFlowCondition ( flags : FlowFlags , antecedent : FlowNode , expression : Expression | undefined ) : FlowNode {
1364+ function createFlowCondition ( flags : FlowFlags . TrueCondition | FlowFlags . FalseCondition , antecedent : FlowNode , expression : Expression | undefined ) {
13601365 if ( antecedent . flags & FlowFlags . Unreachable ) {
13611366 return antecedent ;
13621367 }
@@ -1374,32 +1379,32 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13741379 return antecedent ;
13751380 }
13761381 setFlowNodeReferenced ( antecedent ) ;
1377- return initFlowNode ( { flags, antecedent , node : expression } ) ;
1382+ return createFlowNode ( flags , expression , antecedent ) as FlowCondition ;
13781383 }
13791384
1380- function createFlowSwitchClause ( antecedent : FlowNode , switchStatement : SwitchStatement , clauseStart : number , clauseEnd : number ) : FlowNode {
1385+ function createFlowSwitchClause ( antecedent : FlowNode , switchStatement : SwitchStatement , clauseStart : number , clauseEnd : number ) {
13811386 setFlowNodeReferenced ( antecedent ) ;
1382- return initFlowNode ( { flags : FlowFlags . SwitchClause , antecedent , switchStatement, clauseStart, clauseEnd } ) ;
1387+ return createFlowNode ( FlowFlags . SwitchClause , { switchStatement, clauseStart, clauseEnd } , antecedent ) as FlowSwitchClause ;
13831388 }
13841389
1385- function createFlowMutation ( flags : FlowFlags , antecedent : FlowNode , node : Expression | VariableDeclaration | ArrayBindingElement ) : FlowNode {
1390+ function createFlowMutation ( flags : FlowFlags . Assignment | FlowFlags . ArrayMutation , antecedent : FlowNode , node : Expression | VariableDeclaration | ArrayBindingElement ) {
13861391 setFlowNodeReferenced ( antecedent ) ;
13871392 hasFlowEffects = true ;
1388- const result = initFlowNode ( { flags, antecedent , node } ) ;
1393+ const result = createFlowNode ( flags , node , antecedent ) as FlowAssignment | FlowArrayMutation ;
13891394 if ( currentExceptionTarget ) {
13901395 addAntecedent ( currentExceptionTarget , result ) ;
13911396 }
13921397 return result ;
13931398 }
13941399
1395- function createFlowCall ( antecedent : FlowNode , node : CallExpression ) : FlowNode {
1400+ function createFlowCall ( antecedent : FlowNode , node : CallExpression ) {
13961401 setFlowNodeReferenced ( antecedent ) ;
13971402 hasFlowEffects = true ;
1398- return initFlowNode ( { flags : FlowFlags . Call , antecedent , node } ) ;
1403+ return createFlowNode ( FlowFlags . Call , node , antecedent ) as FlowCall ;
13991404 }
14001405
14011406 function finishFlowLabel ( flow : FlowLabel ) : FlowNode {
1402- const antecedents = flow . antecedents ;
1407+ const antecedents = flow . antecedent ;
14031408 if ( ! antecedents ) {
14041409 return unreachableFlow ;
14051410 }
@@ -1658,7 +1663,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
16581663 // set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel
16591664 // node, the pre-finally label is temporarily switched to the reduced antecedent set.
16601665 const finallyLabel = createBranchLabel ( ) ;
1661- finallyLabel . antecedents = concatenate ( concatenate ( normalExitLabel . antecedents , exceptionLabel . antecedents ) , returnLabel . antecedents ) ;
1666+ finallyLabel . antecedent = concatenate ( concatenate ( normalExitLabel . antecedent , exceptionLabel . antecedent ) , returnLabel . antecedent ) ;
16621667 currentFlow = finallyLabel ;
16631668 bind ( node . finallyBlock ) ;
16641669 if ( currentFlow . flags & FlowFlags . Unreachable ) {
@@ -1668,18 +1673,18 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
16681673 else {
16691674 // If we have an IIFE return target and return statements in the try or catch blocks, add a control
16701675 // flow that goes back through the finally block and back through only the return statements.
1671- if ( currentReturnTarget && returnLabel . antecedents ) {
1672- addAntecedent ( currentReturnTarget , createReduceLabel ( finallyLabel , returnLabel . antecedents , currentFlow ) ) ;
1676+ if ( currentReturnTarget && returnLabel . antecedent ) {
1677+ addAntecedent ( currentReturnTarget , createReduceLabel ( finallyLabel , returnLabel . antecedent , currentFlow ) ) ;
16731678 }
16741679 // If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a
16751680 // control flow that goes back through the finally blok and back through each possible exception source.
1676- if ( currentExceptionTarget && exceptionLabel . antecedents ) {
1677- addAntecedent ( currentExceptionTarget , createReduceLabel ( finallyLabel , exceptionLabel . antecedents , currentFlow ) ) ;
1681+ if ( currentExceptionTarget && exceptionLabel . antecedent ) {
1682+ addAntecedent ( currentExceptionTarget , createReduceLabel ( finallyLabel , exceptionLabel . antecedent , currentFlow ) ) ;
16781683 }
16791684 // If the end of the finally block is reachable, but the end of the try and catch blocks are not,
16801685 // convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should
16811686 // result in an unreachable current control flow.
1682- currentFlow = normalExitLabel . antecedents ? createReduceLabel ( finallyLabel , normalExitLabel . antecedents , currentFlow ) : unreachableFlow ;
1687+ currentFlow = normalExitLabel . antecedent ? createReduceLabel ( finallyLabel , normalExitLabel . antecedent , currentFlow ) : unreachableFlow ;
16831688 }
16841689 }
16851690 else {
@@ -1700,7 +1705,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
17001705 // We mark a switch statement as possibly exhaustive if it has no default clause and if all
17011706 // case clauses have unreachable end points (e.g. they all return). Note, we no longer need
17021707 // this property in control flow analysis, it's there only for backwards compatibility.
1703- node . possiblyExhaustive = ! hasDefault && ! postSwitchLabel . antecedents ;
1708+ node . possiblyExhaustive = ! hasDefault && ! postSwitchLabel . antecedent ;
17041709 if ( ! hasDefault ) {
17051710 addAntecedent ( postSwitchLabel , createFlowSwitchClause ( preSwitchCaseFlow , node , 0 , 0 ) ) ;
17061711 }
@@ -1712,7 +1717,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
17121717 function bindCaseBlock ( node : CaseBlock ) : void {
17131718 const clauses = node . clauses ;
17141719 const isNarrowingSwitch = node . parent . expression . kind === SyntaxKind . TrueKeyword || isNarrowingExpression ( node . parent . expression ) ;
1715- let fallthroughFlow = unreachableFlow ;
1720+ let fallthroughFlow : FlowNode = unreachableFlow ;
17161721
17171722 for ( let i = 0 ; i < clauses . length ; i ++ ) {
17181723 const clauseStart = i ;
@@ -2432,7 +2437,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
24322437 const host = typeAlias . parent . parent ;
24332438 container = ( getEnclosingContainer ( host ) as IsContainer | undefined ) || file ;
24342439 blockScopeContainer = ( getEnclosingBlockScopeContainer ( host ) as IsBlockScopedContainer | undefined ) || file ;
2435- currentFlow = initFlowNode ( { flags : FlowFlags . Start } ) ;
2440+ currentFlow = createFlowNode ( FlowFlags . Start , /*node*/ undefined , /*antecedent*/ undefined ) ;
24362441 parent = typeAlias ;
24372442 bind ( typeAlias . typeExpression ) ;
24382443 const declName = getNameOfDeclaration ( typeAlias ) ;
@@ -2504,7 +2509,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
25042509 const enclosingBlockScopeContainer = host ? getEnclosingBlockScopeContainer ( host ) as IsBlockScopedContainer | undefined : undefined ;
25052510 container = enclosingContainer || file ;
25062511 blockScopeContainer = enclosingBlockScopeContainer || file ;
2507- currentFlow = initFlowNode ( { flags : FlowFlags . Start } ) ;
2512+ currentFlow = createFlowNode ( FlowFlags . Start , /*node*/ undefined , /*antecedent*/ undefined ) ;
25082513 parent = jsDocImportTag ;
25092514 bind ( jsDocImportTag . importClause ) ;
25102515 }
0 commit comments