@@ -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 ,
@@ -105,7 +103,6 @@ import {
105103 getNameOfDeclaration ,
106104 getNameOrArgument ,
107105 getNodeId ,
108- getRangesWhere ,
109106 getRightMostAssignedExpression ,
110107 getSourceFileOfNode ,
111108 getSourceTextOfNodeFromSourceFile ,
@@ -114,10 +111,8 @@ import {
114111 getSymbolNameForPrivateIdentifier ,
115112 getTextOfIdentifierOrLiteral ,
116113 getThisContainer ,
117- getTokenPosOfNode ,
118114 HasContainerFlags ,
119115 hasDynamicName ,
120- HasFlowNode ,
121116 hasJSDocNodes ,
122117 HasLocals ,
123118 hasSyntacticModifier ,
@@ -163,7 +158,6 @@ import {
163158 isExternalModule ,
164159 isExternalOrCommonJsModule ,
165160 isForInOrOfStatement ,
166- isFunctionDeclaration ,
167161 isFunctionLike ,
168162 isFunctionLikeDeclaration ,
169163 isFunctionLikeOrClassStaticBlockDeclaration ,
@@ -203,6 +197,7 @@ import {
203197 isParenthesizedExpression ,
204198 isPartOfParameterDeclaration ,
205199 isPartOfTypeQuery ,
200+ isPotentiallyExecutableNode ,
206201 isPrefixUnaryExpression ,
207202 isPrivateIdentifier ,
208203 isPrologueDirective ,
@@ -216,8 +211,6 @@ import {
216211 isSignedNumericLiteral ,
217212 isSourceFile ,
218213 isSpecialPropertyDeclaration ,
219- isStatement ,
220- isStatementButNotDeclaration ,
221214 isStatic ,
222215 isString ,
223216 isStringLiteralLike ,
@@ -284,10 +277,8 @@ import {
284277 setParentRecursive ,
285278 setValueDeclaration ,
286279 ShorthandPropertyAssignment ,
287- shouldPreserveConstEnums ,
288280 SignatureDeclaration ,
289281 skipParentheses ,
290- sliceAfter ,
291282 some ,
292283 SourceFile ,
293284 SpreadElement ,
@@ -300,7 +291,6 @@ import {
300291 symbolName ,
301292 SymbolTable ,
302293 SyntaxKind ,
303- TextRange ,
304294 ThisExpression ,
305295 ThrowStatement ,
306296 tokenToString ,
@@ -313,8 +303,6 @@ import {
313303 TypeOfExpression ,
314304 TypeParameterDeclaration ,
315305 unescapeLeadingUnderscores ,
316- unreachableCodeIsError ,
317- unusedLabelIsError ,
318306 VariableDeclaration ,
319307 WhileStatement ,
320308 WithStatement ,
@@ -562,7 +550,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
562550 var classifiableNames : Set < __String > ;
563551
564552 var unreachableFlow = createFlowNode ( FlowFlags . Unreachable , /*node*/ undefined , /*antecedent*/ undefined ) ;
565- var reportedUnreachableFlow = createFlowNode ( FlowFlags . Unreachable , /*node*/ undefined , /*antecedent*/ undefined ) ;
566553 var bindBinaryExpressionFlow = createBindBinaryExpressionFlow ( ) ;
567554 /* eslint-enable no-var */
568555
@@ -588,7 +575,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
588575
589576 // Attach debugging information if necessary
590577 Debug . attachFlowNodeDebugInfo ( unreachableFlow ) ;
591- Debug . attachFlowNodeDebugInfo ( reportedUnreachableFlow ) ;
592578
593579 if ( ! file . locals ) {
594580 tracing ?. push ( tracing . Phase . Bind , "bindSourceFile" , { path : file . path } , /*separateBeginAndEnd*/ true ) ;
@@ -1099,18 +1085,24 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
10991085 // Most nodes aren't valid in an assignment pattern, so we clear the value here
11001086 // and set it before we descend into nodes that could actually be part of an assignment pattern.
11011087 inAssignmentPattern = false ;
1102- if ( checkUnreachable ( node ) ) {
1103- if ( canHaveFlowNode ( node ) && node . flowNode ) {
1088+
1089+ if ( currentFlow === unreachableFlow ) {
1090+ if ( canHaveFlowNode ( node ) ) {
11041091 node . flowNode = undefined ;
11051092 }
1093+ if ( isPotentiallyExecutableNode ( node ) ) {
1094+ ( node as Mutable < Node > ) . flags |= NodeFlags . Unreachable ;
1095+ }
11061096 bindEachChild ( node ) ;
11071097 bindJSDoc ( node ) ;
11081098 inAssignmentPattern = saveInAssignmentPattern ;
11091099 return ;
11101100 }
1111- if ( node . kind >= SyntaxKind . FirstStatement && node . kind <= SyntaxKind . LastStatement && ( ! options . allowUnreachableCode || node . kind === SyntaxKind . ReturnStatement ) ) {
1112- ( node as HasFlowNode ) . flowNode = currentFlow ;
1101+
1102+ if ( SyntaxKind . FirstStatement <= node . kind && node . kind <= SyntaxKind . LastStatement && canHaveFlowNode ( node ) ) {
1103+ node . flowNode = currentFlow ;
11131104 }
1105+
11141106 switch ( node . kind ) {
11151107 case SyntaxKind . WhileStatement :
11161108 bindWhileStatement ( node as WhileStatement ) ;
@@ -1788,8 +1780,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
17881780 } ;
17891781 bind ( node . label ) ;
17901782 bind ( node . statement ) ;
1791- if ( ! activeLabelList . referenced && ! options . allowUnusedLabels ) {
1792- errorOrSuggestionOnNode ( unusedLabelIsError ( options ) , node . label , Diagnostics . Unused_label ) ;
1783+ if ( ! activeLabelList . referenced ) {
1784+ ( node . label as Mutable < Node > ) . flags |= NodeFlags . Unreachable ;
17931785 }
17941786 activeLabelList = activeLabelList . next ;
17951787 addAntecedent ( postStatementLabel , currentFlow ) ;
@@ -2708,24 +2700,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
27082700 file . bindDiagnostics . push ( createFileDiagnostic ( file , span . start , span . length , message , ...args ) ) ;
27092701 }
27102702
2711- function errorOrSuggestionOnNode ( isError : boolean , node : Node , message : DiagnosticMessage ) : void {
2712- errorOrSuggestionOnRange ( isError , node , node , message ) ;
2713- }
2714-
2715- function errorOrSuggestionOnRange ( isError : boolean , startNode : Node , endNode : Node , message : DiagnosticMessage ) : void {
2716- addErrorOrSuggestionDiagnostic ( isError , { pos : getTokenPosOfNode ( startNode , file ) , end : endNode . end } , message ) ;
2717- }
2718-
2719- function addErrorOrSuggestionDiagnostic ( isError : boolean , range : TextRange , message : DiagnosticMessage ) : void {
2720- const diag = createFileDiagnostic ( file , range . pos , range . end - range . pos , message ) ;
2721- if ( isError ) {
2722- file . bindDiagnostics . push ( diag ) ;
2723- }
2724- else {
2725- file . bindSuggestionDiagnostics = append ( file . bindSuggestionDiagnostics , { ...diag , category : DiagnosticCategory . Suggestion } ) ;
2726- }
2727- }
2728-
27292703 function bind ( node : Node | undefined ) : void {
27302704 if ( ! node ) {
27312705 return ;
@@ -3757,93 +3731,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
37573731 declareSymbolAndAddToSymbolTable ( node , SymbolFlags . TypeParameter , SymbolFlags . TypeParameterExcludes ) ;
37583732 }
37593733 }
3760-
3761- // reachability checks
3762-
3763- function shouldReportErrorOnModuleDeclaration ( node : ModuleDeclaration ) : boolean {
3764- const instanceState = getModuleInstanceState ( node ) ;
3765- return instanceState === ModuleInstanceState . Instantiated || ( instanceState === ModuleInstanceState . ConstEnumOnly && shouldPreserveConstEnums ( options ) ) ;
3766- }
3767-
3768- function checkUnreachable ( node : Node ) : boolean {
3769- if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) ) {
3770- return false ;
3771- }
3772- if ( currentFlow === unreachableFlow ) {
3773- const reportError =
3774- // report error on all statements except empty ones
3775- ( isStatementButNotDeclaration ( node ) && node . kind !== SyntaxKind . EmptyStatement ) ||
3776- // report error on class declarations
3777- node . kind === SyntaxKind . ClassDeclaration ||
3778- // report errors on enums with preserved emit
3779- isEnumDeclarationWithPreservedEmit ( node , options ) ||
3780- // report error on instantiated modules
3781- ( node . kind === SyntaxKind . ModuleDeclaration && shouldReportErrorOnModuleDeclaration ( node as ModuleDeclaration ) ) ;
3782-
3783- if ( reportError ) {
3784- currentFlow = reportedUnreachableFlow ;
3785-
3786- if ( ! options . allowUnreachableCode ) {
3787- // unreachable code is reported if
3788- // - user has explicitly asked about it AND
3789- // - statement is in not ambient context (statements in ambient context is already an error
3790- // so we should not report extras) AND
3791- // - node is not variable statement OR
3792- // - node is block scoped variable statement OR
3793- // - node is not block scoped variable statement and at least one variable declaration has initializer
3794- // Rationale: we don't want to report errors on non-initialized var's since they are hoisted
3795- // On the other side we do want to report errors on non-initialized 'lets' because of TDZ
3796- const isError = unreachableCodeIsError ( options ) &&
3797- ! ( node . flags & NodeFlags . Ambient ) &&
3798- (
3799- ! isVariableStatement ( node ) ||
3800- ! ! ( getCombinedNodeFlags ( node . declarationList ) & NodeFlags . BlockScoped ) ||
3801- node . declarationList . declarations . some ( d => ! ! d . initializer )
3802- ) ;
3803-
3804- eachUnreachableRange ( node , options , ( start , end ) => errorOrSuggestionOnRange ( isError , start , end , Diagnostics . Unreachable_code_detected ) ) ;
3805- }
3806- }
3807- }
3808- return true ;
3809- }
3810- }
3811-
3812- function isEnumDeclarationWithPreservedEmit ( node : Node , options : CompilerOptions ) : boolean {
3813- return node . kind === SyntaxKind . EnumDeclaration && ( ! isEnumConst ( node as EnumDeclaration ) || shouldPreserveConstEnums ( options ) ) ;
3814- }
3815-
3816- function eachUnreachableRange ( node : Node , options : CompilerOptions , cb : ( start : Node , last : Node ) => void ) : void {
3817- if ( isStatement ( node ) && isExecutableStatement ( node ) && isBlock ( node . parent ) ) {
3818- const { statements } = node . parent ;
3819- const slice = sliceAfter ( statements , node ) ;
3820- getRangesWhere ( slice , isExecutableStatement , ( start , afterEnd ) => cb ( slice [ start ] , slice [ afterEnd - 1 ] ) ) ;
3821- }
3822- else {
3823- cb ( node , node ) ;
3824- }
3825-
3826- // As opposed to a pure declaration like an `interface`
3827- function isExecutableStatement ( s : Statement ) : boolean {
3828- // Don't remove statements that can validly be used before they appear.
3829- return ! isFunctionDeclaration ( s ) && ! isPurelyTypeDeclaration ( s ) &&
3830- // `var x;` may declare a variable used above
3831- ! ( isVariableStatement ( s ) && ! ( getCombinedNodeFlags ( s ) & ( NodeFlags . BlockScoped ) ) && s . declarationList . declarations . some ( d => ! d . initializer ) ) ;
3832- }
3833-
3834- function isPurelyTypeDeclaration ( s : Statement ) : boolean {
3835- switch ( s . kind ) {
3836- case SyntaxKind . InterfaceDeclaration :
3837- case SyntaxKind . TypeAliasDeclaration :
3838- return true ;
3839- case SyntaxKind . ModuleDeclaration :
3840- return getModuleInstanceState ( s as ModuleDeclaration ) !== ModuleInstanceState . Instantiated ;
3841- case SyntaxKind . EnumDeclaration :
3842- return ! isEnumDeclarationWithPreservedEmit ( s , options ) ;
3843- default :
3844- return false ;
3845- }
3846- }
38473734}
38483735
38493736/** @internal */
0 commit comments