@@ -129,15 +129,16 @@ namespace ts {
129
129
let Symbol : { new ( flags : SymbolFlags , name : string ) : Symbol } ;
130
130
let classifiableNames : Map < string > ;
131
131
132
- const unreachableFlow : FlowNode = { kind : FlowKind . Unreachable } ;
133
- const reportedUnreachableFlow : FlowNode = { kind : FlowKind . Unreachable } ;
132
+ const unreachableFlow : FlowNode = { flags : FlowFlags . Unreachable } ;
133
+ const reportedUnreachableFlow : FlowNode = { flags : FlowFlags . Unreachable } ;
134
134
135
135
function bindSourceFile ( f : SourceFile , opts : CompilerOptions ) {
136
136
file = f ;
137
137
options = opts ;
138
138
languageVersion = getEmitScriptTarget ( options ) ;
139
139
inStrictMode = ! ! file . externalModuleIndicator ;
140
140
classifiableNames = { } ;
141
+ symbolCount = 0 ;
141
142
142
143
Symbol = objectAllocator . getSymbolConstructor ( ) ;
143
144
@@ -470,7 +471,7 @@ namespace ts {
470
471
savedActiveLabels = activeLabels ;
471
472
472
473
hasExplicitReturn = false ;
473
- currentFlow = { kind : FlowKind . Start } ;
474
+ currentFlow = { flags : FlowFlags . Start } ;
474
475
currentBreakTarget = undefined ;
475
476
currentContinueTarget = undefined ;
476
477
activeLabels = undefined ;
@@ -482,7 +483,7 @@ namespace ts {
482
483
483
484
bindReachableStatement ( node ) ;
484
485
485
- if ( currentFlow . kind !== FlowKind . Unreachable && isFunctionLikeKind ( kind ) && nodeIsPresent ( ( < FunctionLikeDeclaration > node ) . body ) ) {
486
+ if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) && isFunctionLikeKind ( kind ) && nodeIsPresent ( ( < FunctionLikeDeclaration > node ) . body ) ) {
486
487
flags |= NodeFlags . HasImplicitReturn ;
487
488
if ( hasExplicitReturn ) {
488
489
flags |= NodeFlags . HasExplicitReturn ;
@@ -638,55 +639,80 @@ namespace ts {
638
639
return false ;
639
640
}
640
641
641
- function createFlowLabel ( ) : FlowLabel {
642
+ function createBranchLabel ( ) : FlowLabel {
642
643
return {
643
- kind : FlowKind . Label ,
644
+ flags : FlowFlags . BranchLabel ,
644
645
antecedents : undefined
645
646
} ;
646
647
}
647
648
648
- function createFlowLoopLabel ( ) : FlowLabel {
649
+ function createLoopLabel ( ) : FlowLabel {
649
650
return {
650
- kind : FlowKind . LoopLabel ,
651
+ flags : FlowFlags . LoopLabel ,
651
652
antecedents : undefined
652
653
} ;
653
654
}
654
655
656
+ function setFlowNodeReferenced ( flow : FlowNode ) {
657
+ // On first reference we set the Referenced flag, thereafter we set the Shared flag
658
+ flow . flags |= flow . flags & FlowFlags . Referenced ? FlowFlags . Shared : FlowFlags . Referenced ;
659
+ }
660
+
655
661
function addAntecedent ( label : FlowLabel , antecedent : FlowNode ) : void {
656
- if ( antecedent . kind !== FlowKind . Unreachable && ! contains ( label . antecedents , antecedent ) ) {
662
+ if ( ! ( antecedent . flags & FlowFlags . Unreachable ) && ! contains ( label . antecedents , antecedent ) ) {
657
663
( label . antecedents || ( label . antecedents = [ ] ) ) . push ( antecedent ) ;
664
+ setFlowNodeReferenced ( antecedent ) ;
658
665
}
659
666
}
660
667
661
- function createFlowCondition ( antecedent : FlowNode , expression : Expression , assumeTrue : boolean ) : FlowNode {
662
- if ( antecedent . kind === FlowKind . Unreachable ) {
668
+ function createFlowCondition ( flags : FlowFlags , antecedent : FlowNode , expression : Expression ) : FlowNode {
669
+ if ( antecedent . flags & FlowFlags . Unreachable ) {
663
670
return antecedent ;
664
671
}
665
672
if ( ! expression ) {
666
- return assumeTrue ? antecedent : unreachableFlow ;
673
+ return flags & FlowFlags . TrueCondition ? antecedent : unreachableFlow ;
667
674
}
668
- if ( expression . kind === SyntaxKind . TrueKeyword && ! assumeTrue || expression . kind === SyntaxKind . FalseKeyword && assumeTrue ) {
675
+ if ( expression . kind === SyntaxKind . TrueKeyword && flags & FlowFlags . FalseCondition ||
676
+ expression . kind === SyntaxKind . FalseKeyword && flags & FlowFlags . TrueCondition ) {
669
677
return unreachableFlow ;
670
678
}
671
679
if ( ! isNarrowingExpression ( expression ) ) {
672
680
return antecedent ;
673
681
}
682
+ setFlowNodeReferenced ( antecedent ) ;
674
683
return < FlowCondition > {
675
- kind : FlowKind . Condition ,
684
+ flags ,
676
685
antecedent,
677
686
expression,
678
- assumeTrue
679
687
} ;
680
688
}
681
689
682
690
function createFlowAssignment ( antecedent : FlowNode , node : Expression | VariableDeclaration | BindingElement ) : FlowNode {
691
+ setFlowNodeReferenced ( antecedent ) ;
683
692
return < FlowAssignment > {
684
- kind : FlowKind . Assignment ,
693
+ flags : FlowFlags . Assignment ,
685
694
antecedent,
686
695
node
687
696
} ;
688
697
}
689
698
699
+ function skipSimpleConditionalFlow ( flow : FlowNode ) {
700
+ // We skip over simple conditional flows of the form 'x ? aaa : bbb', where 'aaa' and 'bbb' contain
701
+ // no constructs that affect control flow type analysis. Such simple flows have no effect on the
702
+ // code paths that follow and ignoring them means we'll do less work.
703
+ if ( flow . flags & FlowFlags . BranchLabel && ( < FlowLabel > flow ) . antecedents . length === 2 ) {
704
+ const a = ( < FlowLabel > flow ) . antecedents [ 0 ] ;
705
+ const b = ( < FlowLabel > flow ) . antecedents [ 1 ] ;
706
+ if ( ( a . flags & FlowFlags . TrueCondition && b . flags & FlowFlags . FalseCondition ||
707
+ a . flags & FlowFlags . FalseCondition && b . flags & FlowFlags . TrueCondition ) &&
708
+ ( < FlowCondition > a ) . antecedent === ( < FlowCondition > b ) . antecedent &&
709
+ ( < FlowCondition > a ) . expression === ( < FlowCondition > b ) . expression ) {
710
+ return ( < FlowCondition > a ) . antecedent ;
711
+ }
712
+ }
713
+ return flow ;
714
+ }
715
+
690
716
function finishFlowLabel ( flow : FlowLabel ) : FlowNode {
691
717
const antecedents = flow . antecedents ;
692
718
if ( ! antecedents ) {
@@ -695,7 +721,7 @@ namespace ts {
695
721
if ( antecedents . length === 1 ) {
696
722
return antecedents [ 0 ] ;
697
723
}
698
- return flow ;
724
+ return skipSimpleConditionalFlow ( flow ) ;
699
725
}
700
726
701
727
function isStatementCondition ( node : Node ) {
@@ -746,8 +772,8 @@ namespace ts {
746
772
currentTrueTarget = saveTrueTarget ;
747
773
currentFalseTarget = saveFalseTarget ;
748
774
if ( ! node || ! isLogicalExpression ( node ) ) {
749
- addAntecedent ( trueTarget , createFlowCondition ( currentFlow , node , /*assumeTrue*/ true ) ) ;
750
- addAntecedent ( falseTarget , createFlowCondition ( currentFlow , node , /*assumeTrue*/ false ) ) ;
775
+ addAntecedent ( trueTarget , createFlowCondition ( FlowFlags . TrueCondition , currentFlow , node ) ) ;
776
+ addAntecedent ( falseTarget , createFlowCondition ( FlowFlags . FalseCondition , currentFlow , node ) ) ;
751
777
}
752
778
}
753
779
@@ -762,9 +788,9 @@ namespace ts {
762
788
}
763
789
764
790
function bindWhileStatement ( node : WhileStatement ) : void {
765
- const preWhileLabel = createFlowLoopLabel ( ) ;
766
- const preBodyLabel = createFlowLabel ( ) ;
767
- const postWhileLabel = createFlowLabel ( ) ;
791
+ const preWhileLabel = createLoopLabel ( ) ;
792
+ const preBodyLabel = createBranchLabel ( ) ;
793
+ const postWhileLabel = createBranchLabel ( ) ;
768
794
addAntecedent ( preWhileLabel , currentFlow ) ;
769
795
currentFlow = preWhileLabel ;
770
796
bindCondition ( node . expression , preBodyLabel , postWhileLabel ) ;
@@ -775,9 +801,9 @@ namespace ts {
775
801
}
776
802
777
803
function bindDoStatement ( node : DoStatement ) : void {
778
- const preDoLabel = createFlowLoopLabel ( ) ;
779
- const preConditionLabel = createFlowLabel ( ) ;
780
- const postDoLabel = createFlowLabel ( ) ;
804
+ const preDoLabel = createLoopLabel ( ) ;
805
+ const preConditionLabel = createBranchLabel ( ) ;
806
+ const postDoLabel = createBranchLabel ( ) ;
781
807
addAntecedent ( preDoLabel , currentFlow ) ;
782
808
currentFlow = preDoLabel ;
783
809
bindIterativeStatement ( node . statement , postDoLabel , preConditionLabel ) ;
@@ -788,9 +814,9 @@ namespace ts {
788
814
}
789
815
790
816
function bindForStatement ( node : ForStatement ) : void {
791
- const preLoopLabel = createFlowLoopLabel ( ) ;
792
- const preBodyLabel = createFlowLabel ( ) ;
793
- const postLoopLabel = createFlowLabel ( ) ;
817
+ const preLoopLabel = createLoopLabel ( ) ;
818
+ const preBodyLabel = createBranchLabel ( ) ;
819
+ const postLoopLabel = createBranchLabel ( ) ;
794
820
bind ( node . initializer ) ;
795
821
addAntecedent ( preLoopLabel , currentFlow ) ;
796
822
currentFlow = preLoopLabel ;
@@ -803,8 +829,8 @@ namespace ts {
803
829
}
804
830
805
831
function bindForInOrForOfStatement ( node : ForInStatement | ForOfStatement ) : void {
806
- const preLoopLabel = createFlowLoopLabel ( ) ;
807
- const postLoopLabel = createFlowLabel ( ) ;
832
+ const preLoopLabel = createLoopLabel ( ) ;
833
+ const postLoopLabel = createBranchLabel ( ) ;
808
834
addAntecedent ( preLoopLabel , currentFlow ) ;
809
835
currentFlow = preLoopLabel ;
810
836
bind ( node . expression ) ;
@@ -819,9 +845,9 @@ namespace ts {
819
845
}
820
846
821
847
function bindIfStatement ( node : IfStatement ) : void {
822
- const thenLabel = createFlowLabel ( ) ;
823
- const elseLabel = createFlowLabel ( ) ;
824
- const postIfLabel = createFlowLabel ( ) ;
848
+ const thenLabel = createBranchLabel ( ) ;
849
+ const elseLabel = createBranchLabel ( ) ;
850
+ const postIfLabel = createBranchLabel ( ) ;
825
851
bindCondition ( node . expression , thenLabel , elseLabel ) ;
826
852
currentFlow = finishFlowLabel ( thenLabel ) ;
827
853
bind ( node . thenStatement ) ;
@@ -874,7 +900,7 @@ namespace ts {
874
900
}
875
901
876
902
function bindTryStatement ( node : TryStatement ) : void {
877
- const postFinallyLabel = createFlowLabel ( ) ;
903
+ const postFinallyLabel = createBranchLabel ( ) ;
878
904
const preTryFlow = currentFlow ;
879
905
// TODO: Every statement in try block is potentially an exit point!
880
906
bind ( node . tryBlock ) ;
@@ -892,7 +918,7 @@ namespace ts {
892
918
}
893
919
894
920
function bindSwitchStatement ( node : SwitchStatement ) : void {
895
- const postSwitchLabel = createFlowLabel ( ) ;
921
+ const postSwitchLabel = createBranchLabel ( ) ;
896
922
bind ( node . expression ) ;
897
923
const saveBreakTarget = currentBreakTarget ;
898
924
const savePreSwitchCaseFlow = preSwitchCaseFlow ;
@@ -914,17 +940,17 @@ namespace ts {
914
940
for ( let i = 0 ; i < clauses . length ; i ++ ) {
915
941
const clause = clauses [ i ] ;
916
942
if ( clause . statements . length ) {
917
- if ( currentFlow . kind === FlowKind . Unreachable ) {
943
+ if ( currentFlow . flags & FlowFlags . Unreachable ) {
918
944
currentFlow = preSwitchCaseFlow ;
919
945
}
920
946
else {
921
- const preCaseLabel = createFlowLabel ( ) ;
947
+ const preCaseLabel = createBranchLabel ( ) ;
922
948
addAntecedent ( preCaseLabel , preSwitchCaseFlow ) ;
923
949
addAntecedent ( preCaseLabel , currentFlow ) ;
924
950
currentFlow = finishFlowLabel ( preCaseLabel ) ;
925
951
}
926
952
bind ( clause ) ;
927
- if ( currentFlow . kind !== FlowKind . Unreachable && i !== clauses . length - 1 && options . noFallthroughCasesInSwitch ) {
953
+ if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) && i !== clauses . length - 1 && options . noFallthroughCasesInSwitch ) {
928
954
errorOnFirstToken ( clause , Diagnostics . Fallthrough_case_in_switch ) ;
929
955
}
930
956
}
@@ -950,8 +976,8 @@ namespace ts {
950
976
}
951
977
952
978
function bindLabeledStatement ( node : LabeledStatement ) : void {
953
- const preStatementLabel = createFlowLoopLabel ( ) ;
954
- const postStatementLabel = createFlowLabel ( ) ;
979
+ const preStatementLabel = createLoopLabel ( ) ;
980
+ const postStatementLabel = createBranchLabel ( ) ;
955
981
bind ( node . label ) ;
956
982
addAntecedent ( preStatementLabel , currentFlow ) ;
957
983
const activeLabel = pushActiveLabel ( node . label . text , postStatementLabel , preStatementLabel ) ;
@@ -1000,7 +1026,7 @@ namespace ts {
1000
1026
}
1001
1027
1002
1028
function bindLogicalExpression ( node : BinaryExpression , trueTarget : FlowLabel , falseTarget : FlowLabel ) {
1003
- const preRightLabel = createFlowLabel ( ) ;
1029
+ const preRightLabel = createBranchLabel ( ) ;
1004
1030
if ( node . operatorToken . kind === SyntaxKind . AmpersandAmpersandToken ) {
1005
1031
bindCondition ( node . left , preRightLabel , falseTarget ) ;
1006
1032
}
@@ -1030,7 +1056,7 @@ namespace ts {
1030
1056
const operator = node . operatorToken . kind ;
1031
1057
if ( operator === SyntaxKind . AmpersandAmpersandToken || operator === SyntaxKind . BarBarToken ) {
1032
1058
if ( isTopLevelLogicalExpression ( node ) ) {
1033
- const postExpressionLabel = createFlowLabel ( ) ;
1059
+ const postExpressionLabel = createBranchLabel ( ) ;
1034
1060
bindLogicalExpression ( node , postExpressionLabel , postExpressionLabel ) ;
1035
1061
currentFlow = finishFlowLabel ( postExpressionLabel ) ;
1036
1062
}
@@ -1047,9 +1073,9 @@ namespace ts {
1047
1073
}
1048
1074
1049
1075
function bindConditionalExpressionFlow ( node : ConditionalExpression ) {
1050
- const trueLabel = createFlowLabel ( ) ;
1051
- const falseLabel = createFlowLabel ( ) ;
1052
- const postExpressionLabel = createFlowLabel ( ) ;
1076
+ const trueLabel = createBranchLabel ( ) ;
1077
+ const falseLabel = createBranchLabel ( ) ;
1078
+ const postExpressionLabel = createBranchLabel ( ) ;
1053
1079
bindCondition ( node . condition , trueLabel , falseLabel ) ;
1054
1080
currentFlow = finishFlowLabel ( trueLabel ) ;
1055
1081
bind ( node . whenTrue ) ;
@@ -2064,7 +2090,7 @@ namespace ts {
2064
2090
}
2065
2091
2066
2092
function checkUnreachable ( node : Node ) : boolean {
2067
- if ( currentFlow . kind !== FlowKind . Unreachable ) {
2093
+ if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) ) {
2068
2094
return false ;
2069
2095
}
2070
2096
if ( currentFlow === unreachableFlow ) {
0 commit comments