@@ -46,7 +46,6 @@ import {
4646 DeleteExpression ,
4747 DestructuringAssignment ,
4848 DiagnosticArguments ,
49- DiagnosticCategory ,
5049 DiagnosticMessage ,
5150 DiagnosticRelatedInformation ,
5251 Diagnostics ,
@@ -87,7 +86,6 @@ import {
8786 getAssignmentDeclarationKind ,
8887 getAssignmentDeclarationPropertyAccessKind ,
8988 getCombinedModifierFlags ,
90- getCombinedNodeFlags ,
9189 getContainingClass ,
9290 getEffectiveContainerForJSDocTemplateTag ,
9391 getElementOrPropertyAccessName ,
@@ -106,7 +104,6 @@ import {
106104 getNameOfDeclaration ,
107105 getNameOrArgument ,
108106 getNodeId ,
109- getRangesWhere ,
110107 getRightMostAssignedExpression ,
111108 getSourceFileOfNode ,
112109 getSourceTextOfNodeFromSourceFile ,
@@ -115,10 +112,8 @@ import {
115112 getSymbolNameForPrivateIdentifier ,
116113 getTextOfIdentifierOrLiteral ,
117114 getThisContainer ,
118- getTokenPosOfNode ,
119115 HasContainerFlags ,
120116 hasDynamicName ,
121- HasFlowNode ,
122117 hasJSDocNodes ,
123118 HasLocals ,
124119 hasSyntacticModifier ,
@@ -164,7 +159,6 @@ import {
164159 isExternalModule ,
165160 isExternalOrCommonJsModule ,
166161 isForInOrOfStatement ,
167- isFunctionDeclaration ,
168162 isFunctionLike ,
169163 isFunctionLikeDeclaration ,
170164 isFunctionLikeOrClassStaticBlockDeclaration ,
@@ -204,6 +198,7 @@ import {
204198 isParenthesizedExpression ,
205199 isPartOfParameterDeclaration ,
206200 isPartOfTypeQuery ,
201+ isPotentiallyExecutableNode ,
207202 isPrefixUnaryExpression ,
208203 isPrivateIdentifier ,
209204 isPrologueDirective ,
@@ -217,8 +212,6 @@ import {
217212 isSignedNumericLiteral ,
218213 isSourceFile ,
219214 isSpecialPropertyDeclaration ,
220- isStatement ,
221- isStatementButNotDeclaration ,
222215 isStatic ,
223216 isString ,
224217 isStringLiteralLike ,
@@ -286,10 +279,8 @@ import {
286279 setParentRecursive ,
287280 setValueDeclaration ,
288281 ShorthandPropertyAssignment ,
289- shouldPreserveConstEnums ,
290282 SignatureDeclaration ,
291283 skipParentheses ,
292- sliceAfter ,
293284 some ,
294285 SourceFile ,
295286 SpreadElement ,
@@ -302,7 +293,6 @@ import {
302293 symbolName ,
303294 SymbolTable ,
304295 SyntaxKind ,
305- TextRange ,
306296 ThisExpression ,
307297 ThrowStatement ,
308298 tokenToString ,
@@ -315,8 +305,6 @@ import {
315305 TypeOfExpression ,
316306 TypeParameterDeclaration ,
317307 unescapeLeadingUnderscores ,
318- unreachableCodeIsError ,
319- unusedLabelIsError ,
320308 VariableDeclaration ,
321309 WhileStatement ,
322310 WithStatement ,
@@ -565,7 +553,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
565553 var classifiableNames : Set < __String > ;
566554
567555 var unreachableFlow = createFlowNode ( FlowFlags . Unreachable , /*node*/ undefined , /*antecedent*/ undefined ) ;
568- var reportedUnreachableFlow = createFlowNode ( FlowFlags . Unreachable , /*node*/ undefined , /*antecedent*/ undefined ) ;
569556 var bindBinaryExpressionFlow = createBindBinaryExpressionFlow ( ) ;
570557 /* eslint-enable no-var */
571558
@@ -592,7 +579,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
592579
593580 // Attach debugging information if necessary
594581 Debug . attachFlowNodeDebugInfo ( unreachableFlow ) ;
595- Debug . attachFlowNodeDebugInfo ( reportedUnreachableFlow ) ;
596582
597583 if ( ! file . locals ) {
598584 tracing ?. push ( tracing . Phase . Bind , "bindSourceFile" , { path : file . path } , /*separateBeginAndEnd*/ true ) ;
@@ -1104,18 +1090,24 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
11041090 // Most nodes aren't valid in an assignment pattern, so we clear the value here
11051091 // and set it before we descend into nodes that could actually be part of an assignment pattern.
11061092 inAssignmentPattern = false ;
1107- if ( checkUnreachable ( node ) ) {
1108- if ( canHaveFlowNode ( node ) && node . flowNode ) {
1093+
1094+ if ( currentFlow === unreachableFlow ) {
1095+ if ( canHaveFlowNode ( node ) ) {
11091096 node . flowNode = undefined ;
11101097 }
1098+ if ( isPotentiallyExecutableNode ( node ) ) {
1099+ ( node as Mutable < Node > ) . flags |= NodeFlags . Unreachable ;
1100+ }
11111101 bindEachChild ( node ) ;
11121102 bindJSDoc ( node ) ;
11131103 inAssignmentPattern = saveInAssignmentPattern ;
11141104 return ;
11151105 }
1116- if ( node . kind >= SyntaxKind . FirstStatement && node . kind <= SyntaxKind . LastStatement && ( ! options . allowUnreachableCode || node . kind === SyntaxKind . ReturnStatement ) ) {
1117- ( node as HasFlowNode ) . flowNode = currentFlow ;
1106+
1107+ if ( SyntaxKind . FirstStatement <= node . kind && node . kind <= SyntaxKind . LastStatement && canHaveFlowNode ( node ) ) {
1108+ node . flowNode = currentFlow ;
11181109 }
1110+
11191111 switch ( node . kind ) {
11201112 case SyntaxKind . WhileStatement :
11211113 bindWhileStatement ( node as WhileStatement ) ;
@@ -1793,8 +1785,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
17931785 } ;
17941786 bind ( node . label ) ;
17951787 bind ( node . statement ) ;
1796- if ( ! activeLabelList . referenced && ! options . allowUnusedLabels ) {
1797- errorOrSuggestionOnNode ( unusedLabelIsError ( options ) , node . label , Diagnostics . Unused_label ) ;
1788+ if ( ! activeLabelList . referenced ) {
1789+ ( node . label as Mutable < Node > ) . flags |= NodeFlags . Unreachable ;
17981790 }
17991791 activeLabelList = activeLabelList . next ;
18001792 addAntecedent ( postStatementLabel , currentFlow ) ;
@@ -2743,24 +2735,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
27432735 file . bindDiagnostics . push ( createFileDiagnostic ( file , span . start , span . length , message , ...args ) ) ;
27442736 }
27452737
2746- function errorOrSuggestionOnNode ( isError : boolean , node : Node , message : DiagnosticMessage ) : void {
2747- errorOrSuggestionOnRange ( isError , node , node , message ) ;
2748- }
2749-
2750- function errorOrSuggestionOnRange ( isError : boolean , startNode : Node , endNode : Node , message : DiagnosticMessage ) : void {
2751- addErrorOrSuggestionDiagnostic ( isError , { pos : getTokenPosOfNode ( startNode , file ) , end : endNode . end } , message ) ;
2752- }
2753-
2754- function addErrorOrSuggestionDiagnostic ( isError : boolean , range : TextRange , message : DiagnosticMessage ) : void {
2755- const diag = createFileDiagnostic ( file , range . pos , range . end - range . pos , message ) ;
2756- if ( isError ) {
2757- file . bindDiagnostics . push ( diag ) ;
2758- }
2759- else {
2760- file . bindSuggestionDiagnostics = append ( file . bindSuggestionDiagnostics , { ...diag , category : DiagnosticCategory . Suggestion } ) ;
2761- }
2762- }
2763-
27642738 function bind ( node : Node | undefined ) : void {
27652739 if ( ! node ) {
27662740 return ;
@@ -3793,93 +3767,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
37933767 declareSymbolAndAddToSymbolTable ( node , SymbolFlags . TypeParameter , SymbolFlags . TypeParameterExcludes ) ;
37943768 }
37953769 }
3796-
3797- // reachability checks
3798-
3799- function shouldReportErrorOnModuleDeclaration ( node : ModuleDeclaration ) : boolean {
3800- const instanceState = getModuleInstanceState ( node ) ;
3801- return instanceState === ModuleInstanceState . Instantiated || ( instanceState === ModuleInstanceState . ConstEnumOnly && shouldPreserveConstEnums ( options ) ) ;
3802- }
3803-
3804- function checkUnreachable ( node : Node ) : boolean {
3805- if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) ) {
3806- return false ;
3807- }
3808- if ( currentFlow === unreachableFlow ) {
3809- const reportError =
3810- // report error on all statements except empty ones
3811- ( isStatementButNotDeclaration ( node ) && node . kind !== SyntaxKind . EmptyStatement ) ||
3812- // report error on class declarations
3813- node . kind === SyntaxKind . ClassDeclaration ||
3814- // report errors on enums with preserved emit
3815- isEnumDeclarationWithPreservedEmit ( node , options ) ||
3816- // report error on instantiated modules
3817- ( node . kind === SyntaxKind . ModuleDeclaration && shouldReportErrorOnModuleDeclaration ( node as ModuleDeclaration ) ) ;
3818-
3819- if ( reportError ) {
3820- currentFlow = reportedUnreachableFlow ;
3821-
3822- if ( ! options . allowUnreachableCode ) {
3823- // unreachable code is reported if
3824- // - user has explicitly asked about it AND
3825- // - statement is in not ambient context (statements in ambient context is already an error
3826- // so we should not report extras) AND
3827- // - node is not variable statement OR
3828- // - node is block scoped variable statement OR
3829- // - node is not block scoped variable statement and at least one variable declaration has initializer
3830- // Rationale: we don't want to report errors on non-initialized var's since they are hoisted
3831- // On the other side we do want to report errors on non-initialized 'lets' because of TDZ
3832- const isError = unreachableCodeIsError ( options ) &&
3833- ! ( node . flags & NodeFlags . Ambient ) &&
3834- (
3835- ! isVariableStatement ( node ) ||
3836- ! ! ( getCombinedNodeFlags ( node . declarationList ) & NodeFlags . BlockScoped ) ||
3837- node . declarationList . declarations . some ( d => ! ! d . initializer )
3838- ) ;
3839-
3840- eachUnreachableRange ( node , options , ( start , end ) => errorOrSuggestionOnRange ( isError , start , end , Diagnostics . Unreachable_code_detected ) ) ;
3841- }
3842- }
3843- }
3844- return true ;
3845- }
3846- }
3847-
3848- function isEnumDeclarationWithPreservedEmit ( node : Node , options : CompilerOptions ) : boolean {
3849- return node . kind === SyntaxKind . EnumDeclaration && ( ! isEnumConst ( node as EnumDeclaration ) || shouldPreserveConstEnums ( options ) ) ;
3850- }
3851-
3852- function eachUnreachableRange ( node : Node , options : CompilerOptions , cb : ( start : Node , last : Node ) => void ) : void {
3853- if ( isStatement ( node ) && isExecutableStatement ( node ) && isBlock ( node . parent ) ) {
3854- const { statements } = node . parent ;
3855- const slice = sliceAfter ( statements , node ) ;
3856- getRangesWhere ( slice , isExecutableStatement , ( start , afterEnd ) => cb ( slice [ start ] , slice [ afterEnd - 1 ] ) ) ;
3857- }
3858- else {
3859- cb ( node , node ) ;
3860- }
3861-
3862- // As opposed to a pure declaration like an `interface`
3863- function isExecutableStatement ( s : Statement ) : boolean {
3864- // Don't remove statements that can validly be used before they appear.
3865- return ! isFunctionDeclaration ( s ) && ! isPurelyTypeDeclaration ( s ) &&
3866- // `var x;` may declare a variable used above
3867- ! ( isVariableStatement ( s ) && ! ( getCombinedNodeFlags ( s ) & ( NodeFlags . BlockScoped ) ) && s . declarationList . declarations . some ( d => ! d . initializer ) ) ;
3868- }
3869-
3870- function isPurelyTypeDeclaration ( s : Statement ) : boolean {
3871- switch ( s . kind ) {
3872- case SyntaxKind . InterfaceDeclaration :
3873- case SyntaxKind . TypeAliasDeclaration :
3874- return true ;
3875- case SyntaxKind . ModuleDeclaration :
3876- return getModuleInstanceState ( s as ModuleDeclaration ) !== ModuleInstanceState . Instantiated ;
3877- case SyntaxKind . EnumDeclaration :
3878- return ! isEnumDeclarationWithPreservedEmit ( s , options ) ;
3879- default :
3880- return false ;
3881- }
3882- }
38833770}
38843771
38853772/** @internal */
0 commit comments