@@ -42,10 +42,9 @@ const (
4242)
4343
4444type Binder struct {
45- file * ast.SourceFile
46- bindFunc func (* ast.Node ) bool
47- unreachableFlow * ast.FlowNode
48- reportedUnreachableFlow * ast.FlowNode
45+ file * ast.SourceFile
46+ bindFunc func (* ast.Node ) bool
47+ unreachableFlow * ast.FlowNode
4948
5049 container * ast.Node
5150 thisContainer * ast.Node
@@ -122,7 +121,6 @@ func bindSourceFile(file *ast.SourceFile) {
122121 b .file = file
123122 b .inStrictMode = b .options ().BindInStrictMode && ! file .IsDeclarationFile || ast .IsExternalModule (file )
124123 b .unreachableFlow = b .newFlowNode (ast .FlowFlagsUnreachable )
125- b .reportedUnreachableFlow = b .newFlowNode (ast .FlowFlagsUnreachable )
126124 b .bind (file .AsNode ())
127125 file .SymbolCount = b .symbolCount
128126 file .ClassifiableNames = b .classifiableNames
@@ -1535,18 +1533,25 @@ func (b *Binder) bindChildren(node *ast.Node) {
15351533 // Most nodes aren't valid in an assignment pattern, so we clear the value here
15361534 // and set it before we descend into nodes that could actually be part of an assignment pattern.
15371535 b .inAssignmentPattern = false
1538- if b .checkUnreachable (node ) {
1536+
1537+ if b .currentFlow == b .unreachableFlow {
1538+ if flowNodeData := node .FlowNodeData (); flowNodeData != nil {
1539+ flowNodeData .FlowNode = nil
1540+ }
1541+ if ast .IsPotentiallyExecutableNode (node ) {
1542+ node .Flags |= ast .NodeFlagsUnreachable
1543+ }
15391544 b .bindEachChild (node )
15401545 b .inAssignmentPattern = saveInAssignmentPattern
15411546 return
15421547 }
1543- kind := node .Kind
1544- if kind >= ast .KindFirstStatement && kind <= ast .KindLastStatement && (b .options ().AllowUnreachableCode != core .TSTrue || kind == ast .KindReturnStatement ) {
1545- hasFlowNodeData := node .FlowNodeData ()
1546- if hasFlowNodeData != nil {
1547- hasFlowNodeData .FlowNode = b .currentFlow
1548+
1549+ if ast .KindFirstStatement <= node .Kind && node .Kind <= ast .KindLastStatement {
1550+ if flowNodeData := node .FlowNodeData (); flowNodeData != nil {
1551+ flowNodeData .FlowNode = b .currentFlow
15481552 }
15491553 }
1554+
15501555 switch node .Kind {
15511556 case ast .KindWhileStatement :
15521557 b .bindWhileStatement (node )
@@ -1657,94 +1662,6 @@ func (b *Binder) bindEachStatementFunctionsFirst(statements *ast.NodeList) {
16571662 }
16581663}
16591664
1660- func (b * Binder ) checkUnreachable (node * ast.Node ) bool {
1661- if b .currentFlow .Flags & ast .FlowFlagsUnreachable == 0 {
1662- return false
1663- }
1664- if b .currentFlow == b .unreachableFlow {
1665- // report errors on all statements except empty ones
1666- // report errors on class declarations
1667- // report errors on enums with preserved emit
1668- // report errors on instantiated modules
1669- reportError := ast .IsStatementButNotDeclaration (node ) && ! ast .IsEmptyStatement (node ) ||
1670- ast .IsClassDeclaration (node ) ||
1671- isEnumDeclarationWithPreservedEmit (node , b .options ()) ||
1672- ast .IsModuleDeclaration (node ) && b .shouldReportErrorOnModuleDeclaration (node )
1673- if reportError {
1674- b .currentFlow = b .reportedUnreachableFlow
1675- if b .options ().AllowUnreachableCode != core .TSTrue {
1676- // unreachable code is reported if
1677- // - user has explicitly asked about it AND
1678- // - statement is in not ambient context (statements in ambient context is already an error
1679- // so we should not report extras) AND
1680- // - node is not variable statement OR
1681- // - node is block scoped variable statement OR
1682- // - node is not block scoped variable statement and at least one variable declaration has initializer
1683- // Rationale: we don't want to report errors on non-initialized var's since they are hoisted
1684- // On the other side we do want to report errors on non-initialized 'lets' because of TDZ
1685- isError := unreachableCodeIsError (b .options ()) && node .Flags & ast .NodeFlagsAmbient == 0 && (! ast .IsVariableStatement (node ) ||
1686- ast .GetCombinedNodeFlags (node .AsVariableStatement ().DeclarationList )& ast .NodeFlagsBlockScoped != 0 ||
1687- core .Some (node .AsVariableStatement ().DeclarationList .AsVariableDeclarationList ().Declarations .Nodes , func (d * ast.Node ) bool {
1688- return d .Initializer () != nil
1689- }))
1690- b .errorOnEachUnreachableRange (node , isError )
1691- }
1692- }
1693- }
1694- return true
1695- }
1696-
1697- func (b * Binder ) shouldReportErrorOnModuleDeclaration (node * ast.Node ) bool {
1698- instanceState := ast .GetModuleInstanceState (node )
1699- return instanceState == ast .ModuleInstanceStateInstantiated || (instanceState == ast .ModuleInstanceStateConstEnumOnly && b .options ().ShouldPreserveConstEnums )
1700- }
1701-
1702- func (b * Binder ) errorOnEachUnreachableRange (node * ast.Node , isError bool ) {
1703- if b .isExecutableStatement (node ) && ast .IsBlock (node .Parent ) {
1704- statements := node .Parent .Statements ()
1705- index := slices .Index (statements , node )
1706- var first , last * ast.Node
1707- for _ , s := range statements [index :] {
1708- if b .isExecutableStatement (s ) {
1709- if first == nil {
1710- first = s
1711- }
1712- last = s
1713- } else if first != nil {
1714- b .errorOrSuggestionOnRange (isError , first , last , diagnostics .Unreachable_code_detected )
1715- first = nil
1716- }
1717- }
1718- if first != nil {
1719- b .errorOrSuggestionOnRange (isError , first , last , diagnostics .Unreachable_code_detected )
1720- }
1721- } else {
1722- b .errorOrSuggestionOnNode (isError , node , diagnostics .Unreachable_code_detected )
1723- }
1724- }
1725-
1726- // As opposed to a pure declaration like an `interface`
1727- func (b * Binder ) isExecutableStatement (s * ast.Node ) bool {
1728- // Don't remove statements that can validly be used before they appear.
1729- return ! ast .IsFunctionDeclaration (s ) && ! b .isPurelyTypeDeclaration (s ) && ! (ast .IsVariableStatement (s ) && ast .GetCombinedNodeFlags (s )& ast .NodeFlagsBlockScoped == 0 &&
1730- core .Some (s .AsVariableStatement ().DeclarationList .AsVariableDeclarationList ().Declarations .Nodes , func (d * ast.Node ) bool {
1731- return d .Initializer () == nil
1732- }))
1733- }
1734-
1735- func (b * Binder ) isPurelyTypeDeclaration (s * ast.Node ) bool {
1736- switch s .Kind {
1737- case ast .KindInterfaceDeclaration , ast .KindTypeAliasDeclaration , ast .KindJSTypeAliasDeclaration :
1738- return true
1739- case ast .KindModuleDeclaration :
1740- return ast .GetModuleInstanceState (s ) != ast .ModuleInstanceStateInstantiated
1741- case ast .KindEnumDeclaration :
1742- return ! isEnumDeclarationWithPreservedEmit (s , b .options ())
1743- default :
1744- return false
1745- }
1746- }
1747-
17481665func (b * Binder ) setContinueTarget (node * ast.Node , target * ast.FlowLabel ) * ast.FlowLabel {
17491666 label := b .activeLabelList
17501667 for label != nil && node .Parent .Kind == ast .KindLabeledStatement {
@@ -2131,8 +2048,9 @@ func (b *Binder) bindLabeledStatement(node *ast.Node) {
21312048 }
21322049 b .bind (stmt .Label )
21332050 b .bind (stmt .Statement )
2134- if ! b .activeLabelList .referenced && b .options ().AllowUnusedLabels != core .TSTrue {
2135- b .errorOrSuggestionOnNode (unusedLabelIsError (b .options ()), stmt .Label , diagnostics .Unused_label )
2051+ if ! b .activeLabelList .referenced {
2052+ // Mark the label as unused; the checker will decide whether to report it
2053+ stmt .Label .Flags |= ast .NodeFlagsUnreachable
21362054 }
21372055 b .activeLabelList = b .activeLabelList .next
21382056 b .addAntecedent (postStatementLabel , b .currentFlow )
@@ -2454,10 +2372,6 @@ func (b *Binder) bindInitializer(node *ast.Node) {
24542372 b .currentFlow = b .finishFlowLabel (exitFlow )
24552373}
24562374
2457- func isEnumDeclarationWithPreservedEmit (node * ast.Node , options core.SourceFileAffectingCompilerOptions ) bool {
2458- return node .Kind == ast .KindEnumDeclaration && (! ast .IsEnumConst (node ) || options .ShouldPreserveConstEnums )
2459- }
2460-
24612375func setFlowNode (node * ast.Node , flowNode * ast.FlowNode ) {
24622376 data := node .FlowNodeData ()
24632377 if data != nil {
@@ -2749,14 +2663,6 @@ func isFunctionSymbol(symbol *ast.Symbol) bool {
27492663 return false
27502664}
27512665
2752- func unreachableCodeIsError (options core.SourceFileAffectingCompilerOptions ) bool {
2753- return options .AllowUnreachableCode == core .TSFalse
2754- }
2755-
2756- func unusedLabelIsError (options core.SourceFileAffectingCompilerOptions ) bool {
2757- return options .AllowUnusedLabels == core .TSFalse
2758- }
2759-
27602666func isStatementCondition (node * ast.Node ) bool {
27612667 switch node .Parent .Kind {
27622668 case ast .KindIfStatement , ast .KindWhileStatement , ast .KindDoStatement :
0 commit comments