@@ -65,10 +65,15 @@ import {
65
65
Expression ,
66
66
ExpressionStatement ,
67
67
findAncestor ,
68
+ FlowArrayMutation ,
69
+ FlowAssignment ,
70
+ FlowCall ,
71
+ FlowCondition ,
68
72
FlowFlags ,
69
73
FlowLabel ,
70
74
FlowNode ,
71
75
FlowReduceLabel ,
76
+ FlowSwitchClause ,
72
77
forEach ,
73
78
forEachChild ,
74
79
ForInOrOfStatement ,
@@ -494,9 +499,9 @@ export const enum ContainerFlags {
494
499
IsObjectLiteralOrClassExpressionMethodOrAccessor = 1 << 7 ,
495
500
}
496
501
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 ) ;
500
505
}
501
506
502
507
const binder = /* @__PURE__ */ createBinder ( ) ;
@@ -557,8 +562,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
557
562
var Symbol : new ( flags : SymbolFlags , name : __String ) => Symbol ;
558
563
var classifiableNames : Set < __String > ;
559
564
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 ) ;
562
567
var bindBinaryExpressionFlow = createBindBinaryExpressionFlow ( ) ;
563
568
/* eslint-enable no-var */
564
569
@@ -1013,7 +1018,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1013
1018
// A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
1014
1019
// similarly to break statements that exit to a label just past the statement body.
1015
1020
if ( ! isImmediatelyInvoked ) {
1016
- currentFlow = initFlowNode ( { flags : FlowFlags . Start } ) ;
1021
+ currentFlow = createFlowNode ( FlowFlags . Start , /*node*/ undefined , /*antecedent*/ undefined ) ;
1017
1022
if ( containerFlags & ( ContainerFlags . IsFunctionExpression | ContainerFlags . IsObjectLiteralOrClassExpressionMethodOrAccessor ) ) {
1018
1023
currentFlow . node = node as FunctionExpression | ArrowFunction | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration ;
1019
1024
}
@@ -1332,16 +1337,16 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1332
1337
return containsNarrowableReference ( expr ) ;
1333
1338
}
1334
1339
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 ;
1337
1342
}
1338
1343
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 ;
1341
1346
}
1342
1347
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 ;
1345
1350
}
1346
1351
1347
1352
function setFlowNodeReferenced ( flow : FlowNode ) {
@@ -1350,13 +1355,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1350
1355
}
1351
1356
1352
1357
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 ) ;
1355
1360
setFlowNodeReferenced ( antecedent ) ;
1356
1361
}
1357
1362
}
1358
1363
1359
- function createFlowCondition ( flags : FlowFlags , antecedent : FlowNode , expression : Expression | undefined ) : FlowNode {
1364
+ function createFlowCondition ( flags : FlowFlags . TrueCondition | FlowFlags . FalseCondition , antecedent : FlowNode , expression : Expression | undefined ) {
1360
1365
if ( antecedent . flags & FlowFlags . Unreachable ) {
1361
1366
return antecedent ;
1362
1367
}
@@ -1374,32 +1379,32 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1374
1379
return antecedent ;
1375
1380
}
1376
1381
setFlowNodeReferenced ( antecedent ) ;
1377
- return initFlowNode ( { flags, antecedent , node : expression } ) ;
1382
+ return createFlowNode ( flags , expression , antecedent ) as FlowCondition ;
1378
1383
}
1379
1384
1380
- function createFlowSwitchClause ( antecedent : FlowNode , switchStatement : SwitchStatement , clauseStart : number , clauseEnd : number ) : FlowNode {
1385
+ function createFlowSwitchClause ( antecedent : FlowNode , switchStatement : SwitchStatement , clauseStart : number , clauseEnd : number ) {
1381
1386
setFlowNodeReferenced ( antecedent ) ;
1382
- return initFlowNode ( { flags : FlowFlags . SwitchClause , antecedent , switchStatement, clauseStart, clauseEnd } ) ;
1387
+ return createFlowNode ( FlowFlags . SwitchClause , { switchStatement, clauseStart, clauseEnd } , antecedent ) as FlowSwitchClause ;
1383
1388
}
1384
1389
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 ) {
1386
1391
setFlowNodeReferenced ( antecedent ) ;
1387
1392
hasFlowEffects = true ;
1388
- const result = initFlowNode ( { flags, antecedent , node } ) ;
1393
+ const result = createFlowNode ( flags , node , antecedent ) as FlowAssignment | FlowArrayMutation ;
1389
1394
if ( currentExceptionTarget ) {
1390
1395
addAntecedent ( currentExceptionTarget , result ) ;
1391
1396
}
1392
1397
return result ;
1393
1398
}
1394
1399
1395
- function createFlowCall ( antecedent : FlowNode , node : CallExpression ) : FlowNode {
1400
+ function createFlowCall ( antecedent : FlowNode , node : CallExpression ) {
1396
1401
setFlowNodeReferenced ( antecedent ) ;
1397
1402
hasFlowEffects = true ;
1398
- return initFlowNode ( { flags : FlowFlags . Call , antecedent , node } ) ;
1403
+ return createFlowNode ( FlowFlags . Call , node , antecedent ) as FlowCall ;
1399
1404
}
1400
1405
1401
1406
function finishFlowLabel ( flow : FlowLabel ) : FlowNode {
1402
- const antecedents = flow . antecedents ;
1407
+ const antecedents = flow . antecedent ;
1403
1408
if ( ! antecedents ) {
1404
1409
return unreachableFlow ;
1405
1410
}
@@ -1658,7 +1663,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1658
1663
// set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel
1659
1664
// node, the pre-finally label is temporarily switched to the reduced antecedent set.
1660
1665
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 ) ;
1662
1667
currentFlow = finallyLabel ;
1663
1668
bind ( node . finallyBlock ) ;
1664
1669
if ( currentFlow . flags & FlowFlags . Unreachable ) {
@@ -1668,18 +1673,18 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1668
1673
else {
1669
1674
// If we have an IIFE return target and return statements in the try or catch blocks, add a control
1670
1675
// 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 ) ) ;
1673
1678
}
1674
1679
// If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a
1675
1680
// 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 ) ) ;
1678
1683
}
1679
1684
// If the end of the finally block is reachable, but the end of the try and catch blocks are not,
1680
1685
// convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should
1681
1686
// 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 ;
1683
1688
}
1684
1689
}
1685
1690
else {
@@ -1700,7 +1705,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1700
1705
// We mark a switch statement as possibly exhaustive if it has no default clause and if all
1701
1706
// case clauses have unreachable end points (e.g. they all return). Note, we no longer need
1702
1707
// 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 ;
1704
1709
if ( ! hasDefault ) {
1705
1710
addAntecedent ( postSwitchLabel , createFlowSwitchClause ( preSwitchCaseFlow , node , 0 , 0 ) ) ;
1706
1711
}
@@ -1712,7 +1717,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1712
1717
function bindCaseBlock ( node : CaseBlock ) : void {
1713
1718
const clauses = node . clauses ;
1714
1719
const isNarrowingSwitch = node . parent . expression . kind === SyntaxKind . TrueKeyword || isNarrowingExpression ( node . parent . expression ) ;
1715
- let fallthroughFlow = unreachableFlow ;
1720
+ let fallthroughFlow : FlowNode = unreachableFlow ;
1716
1721
1717
1722
for ( let i = 0 ; i < clauses . length ; i ++ ) {
1718
1723
const clauseStart = i ;
@@ -2432,7 +2437,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
2432
2437
const host = typeAlias . parent . parent ;
2433
2438
container = ( getEnclosingContainer ( host ) as IsContainer | undefined ) || file ;
2434
2439
blockScopeContainer = ( getEnclosingBlockScopeContainer ( host ) as IsBlockScopedContainer | undefined ) || file ;
2435
- currentFlow = initFlowNode ( { flags : FlowFlags . Start } ) ;
2440
+ currentFlow = createFlowNode ( FlowFlags . Start , /*node*/ undefined , /*antecedent*/ undefined ) ;
2436
2441
parent = typeAlias ;
2437
2442
bind ( typeAlias . typeExpression ) ;
2438
2443
const declName = getNameOfDeclaration ( typeAlias ) ;
@@ -2504,7 +2509,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
2504
2509
const enclosingBlockScopeContainer = host ? getEnclosingBlockScopeContainer ( host ) as IsBlockScopedContainer | undefined : undefined ;
2505
2510
container = enclosingContainer || file ;
2506
2511
blockScopeContainer = enclosingBlockScopeContainer || file ;
2507
- currentFlow = initFlowNode ( { flags : FlowFlags . Start } ) ;
2512
+ currentFlow = createFlowNode ( FlowFlags . Start , /*node*/ undefined , /*antecedent*/ undefined ) ;
2508
2513
parent = jsDocImportTag ;
2509
2514
bind ( jsDocImportTag . importClause ) ;
2510
2515
}
0 commit comments