Skip to content

Commit ea33899

Browse files
committed
Mark all unreachable executable statements in cases and source files
1 parent 45e5a45 commit ea33899

File tree

11 files changed

+297
-23
lines changed

11 files changed

+297
-23
lines changed

‎src/compiler/binder.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ import {
213213
isSpecialPropertyDeclaration,
214214
isStatement,
215215
isStatementButNotDeclaration,
216+
isStatementsContainer,
216217
isStatic,
217218
isString,
218219
isStringLiteralLike,
@@ -3729,7 +3730,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
37293730
}
37303731

37313732
function eachUnreachableRange(node: Node, cb: (start: Node, last: Node) => void): void {
3732-
if (isStatement(node) && isExecutableStatement(node) && isBlock(node.parent)) {
3733+
if (isStatement(node) && isExecutableStatement(node) && isStatementsContainer(node.parent)) {
37333734
const { statements } = node.parent;
37343735
const slice = sliceAfter(statements, node);
37353736
getRangesWhere(slice, isExecutableStatement, (start, afterEnd) => cb(slice[start], slice[afterEnd - 1]));

‎src/compiler/types.ts‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3230,6 +3230,10 @@ export interface Statement extends Node, JSDocContainer {
32303230
_statementBrand: any;
32313231
}
32323232

3233+
export interface StatementsContainer extends Node {
3234+
readonly statements: NodeArray<Statement>;
3235+
}
3236+
32333237
// Represents a statement that is elided as part of a transformation to emit comments on a
32343238
// not-emitted node.
32353239
export interface NotEmittedStatement extends Statement {
@@ -3273,9 +3277,8 @@ export type BlockLike =
32733277
| ModuleBlock
32743278
| CaseOrDefaultClause;
32753279

3276-
export interface Block extends Statement, LocalsContainer {
3280+
export interface Block extends Statement, LocalsContainer, StatementsContainer {
32773281
readonly kind: SyntaxKind.Block;
3278-
readonly statements: NodeArray<Statement>;
32793282
/** @internal */ multiLine?: boolean;
32803283
}
32813284

@@ -3382,18 +3385,16 @@ export interface CaseBlock extends Node, LocalsContainer {
33823385
readonly clauses: NodeArray<CaseOrDefaultClause>;
33833386
}
33843387

3385-
export interface CaseClause extends Node, JSDocContainer {
3388+
export interface CaseClause extends StatementsContainer, JSDocContainer {
33863389
readonly kind: SyntaxKind.CaseClause;
33873390
readonly parent: CaseBlock;
33883391
readonly expression: Expression;
3389-
readonly statements: NodeArray<Statement>;
33903392
/** @internal */ fallthroughFlowNode?: FlowNode;
33913393
}
33923394

3393-
export interface DefaultClause extends Node {
3395+
export interface DefaultClause extends StatementsContainer {
33943396
readonly kind: SyntaxKind.DefaultClause;
33953397
readonly parent: CaseBlock;
3396-
readonly statements: NodeArray<Statement>;
33973398
/** @internal */ fallthroughFlowNode?: FlowNode;
33983399
}
33993400

@@ -3558,10 +3559,9 @@ export interface JSDocNamespaceDeclaration extends ModuleDeclaration {
35583559
readonly body?: JSDocNamespaceBody;
35593560
}
35603561

3561-
export interface ModuleBlock extends Node, Statement {
3562+
export interface ModuleBlock extends StatementsContainer, Statement {
35623563
readonly kind: SyntaxKind.ModuleBlock;
35633564
readonly parent: ModuleDeclaration;
3564-
readonly statements: NodeArray<Statement>;
35653565
}
35663566

35673567
export type ModuleReference =
@@ -4150,9 +4150,8 @@ export interface RedirectInfo {
41504150
export type ResolutionMode = ModuleKind.ESNext | ModuleKind.CommonJS | undefined;
41514151

41524152
// Source files are declarations when they are external modules.
4153-
export interface SourceFile extends Declaration, LocalsContainer {
4153+
export interface SourceFile extends Declaration, LocalsContainer, StatementsContainer {
41544154
readonly kind: SyntaxKind.SourceFile;
4155-
readonly statements: NodeArray<Statement>;
41564155
readonly endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
41574156

41584157
fileName: string;

‎src/compiler/utilities.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ import {
492492
startsWith,
493493
startsWithUseStrict,
494494
Statement,
495+
StatementsContainer,
495496
StringLiteral,
496497
StringLiteralLike,
497498
StringLiteralType,
@@ -4619,6 +4620,19 @@ export function isNodeWithPossibleHoistedDeclaration(node: Node): node is NodeWi
46194620
return false;
46204621
}
46214622

4623+
/** @internal */
4624+
export function isStatementsContainer(node: Node): node is StatementsContainer {
4625+
switch (node.kind) {
4626+
case SyntaxKind.Block:
4627+
case SyntaxKind.ModuleBlock:
4628+
case SyntaxKind.SourceFile:
4629+
case SyntaxKind.DefaultClause:
4630+
case SyntaxKind.CaseClause:
4631+
return true;
4632+
}
4633+
return false;
4634+
}
4635+
46224636
/** @internal */
46234637
export type ValueSignatureDeclaration =
46244638
| FunctionDeclaration

‎tests/baselines/reference/api/typescript.d.ts‎

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5693,6 +5693,9 @@ declare namespace ts {
56935693
interface Statement extends Node, JSDocContainer {
56945694
_statementBrand: any;
56955695
}
5696+
interface StatementsContainer extends Node {
5697+
readonly statements: NodeArray<Statement>;
5698+
}
56965699
interface NotEmittedStatement extends Statement {
56975700
readonly kind: SyntaxKind.NotEmittedStatement;
56985701
}
@@ -5714,9 +5717,8 @@ declare namespace ts {
57145717
readonly name?: Identifier;
57155718
}
57165719
type BlockLike = SourceFile | Block | ModuleBlock | CaseOrDefaultClause;
5717-
interface Block extends Statement, LocalsContainer {
5720+
interface Block extends Statement, LocalsContainer, StatementsContainer {
57185721
readonly kind: SyntaxKind.Block;
5719-
readonly statements: NodeArray<Statement>;
57205722
}
57215723
interface VariableStatement extends Statement, FlowContainer {
57225724
readonly kind: SyntaxKind.VariableStatement;
@@ -5792,16 +5794,14 @@ declare namespace ts {
57925794
readonly parent: SwitchStatement;
57935795
readonly clauses: NodeArray<CaseOrDefaultClause>;
57945796
}
5795-
interface CaseClause extends Node, JSDocContainer {
5797+
interface CaseClause extends StatementsContainer, JSDocContainer {
57965798
readonly kind: SyntaxKind.CaseClause;
57975799
readonly parent: CaseBlock;
57985800
readonly expression: Expression;
5799-
readonly statements: NodeArray<Statement>;
58005801
}
5801-
interface DefaultClause extends Node {
5802+
interface DefaultClause extends StatementsContainer {
58025803
readonly kind: SyntaxKind.DefaultClause;
58035804
readonly parent: CaseBlock;
5804-
readonly statements: NodeArray<Statement>;
58055805
}
58065806
type CaseOrDefaultClause = CaseClause | DefaultClause;
58075807
interface LabeledStatement extends Statement, FlowContainer {
@@ -5907,10 +5907,9 @@ declare namespace ts {
59075907
readonly name: Identifier;
59085908
readonly body?: JSDocNamespaceBody;
59095909
}
5910-
interface ModuleBlock extends Node, Statement {
5910+
interface ModuleBlock extends StatementsContainer, Statement {
59115911
readonly kind: SyntaxKind.ModuleBlock;
59125912
readonly parent: ModuleDeclaration;
5913-
readonly statements: NodeArray<Statement>;
59145913
}
59155914
type ModuleReference = EntityName | ExternalModuleReference;
59165915
/**
@@ -6364,9 +6363,8 @@ declare namespace ts {
63646363
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
63656364
}
63666365
type ResolutionMode = ModuleKind.ESNext | ModuleKind.CommonJS | undefined;
6367-
interface SourceFile extends Declaration, LocalsContainer {
6366+
interface SourceFile extends Declaration, LocalsContainer, StatementsContainer {
63686367
readonly kind: SyntaxKind.SourceFile;
6369-
readonly statements: NodeArray<Statement>;
63706368
readonly endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
63716369
fileName: string;
63726370
text: string;

‎tests/baselines/reference/reachabilityChecks1.errors.txt‎

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,86 @@ reachabilityChecks1.ts(6,5): error TS7027: Unreachable code detected.
33
reachabilityChecks1.ts(18,5): error TS7027: Unreachable code detected.
44
reachabilityChecks1.ts(30,5): error TS7027: Unreachable code detected.
55
reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected.
6+
reachabilityChecks1.ts(51,1): error TS7027: Unreachable code detected.
67

78

8-
==== reachabilityChecks1.ts (5 errors) ====
9+
==== reachabilityChecks1.ts (6 errors) ====
910
while (true);
1011
var x = 1;
1112
~~~~~~~~~~
12-
!!! error TS7027: Unreachable code detected.
13+
1314

1415
module A {
16+
~~~~~~~~~~
1517
while (true);
18+
~~~~~~~~~~~~~~~~~
1619
let x;
20+
~~~~~~~~~~
1721
~~~~~~
1822
!!! error TS7027: Unreachable code detected.
1923
}
24+
~
25+
2026

2127
module A1 {
28+
~~~~~~~~~~~
2229
do {} while(true);
30+
~~~~~~~~~~~~~~~~~~~~~~
2331
module A {
32+
~~~~~~~~~~~~~~
2433
interface F {}
34+
~~~~~~~~~~~~~~~~~~~~~~
2535
}
36+
~~~~~
2637
}
38+
~
39+
2740

2841
module A2 {
42+
~~~~~~~~~~~
2943
while (true);
44+
~~~~~~~~~~~~~~~~~
3045
module A {
46+
~~~~~~~~~~~~~~
3147
~~~~~~~~~~
3248
var x = 1;
49+
~~~~~~~~~~~~~~~~~~
3350
~~~~~~~~~~~~~~~~~~
3451
}
3552
~~~~~
53+
~~~~~
3654
!!! error TS7027: Unreachable code detected.
3755
}
56+
~
57+
3858

3959
module A3 {
60+
~~~~~~~~~~~
4061
while (true);
62+
~~~~~~~~~~~~~~~~~
4163
type T = string;
64+
~~~~~~~~~~~~~~~~~~~~
4265
}
66+
~
67+
4368

4469
module A4 {
70+
~~~~~~~~~~~
4571
while (true);
72+
~~~~~~~~~~~~~~~~~
4673
module A {
74+
~~~~~~~~~~~~~~
4775
~~~~~~~~~~
4876
const enum E { X }
77+
~~~~~~~~~~~~~~~~~~~~~~~~~~
4978
~~~~~~~~~~~~~~~~~~~~~~~~~~
5079
}
5180
~~~~~
81+
~~~~~
5282
!!! error TS7027: Unreachable code detected.
5383
}
84+
~
85+
!!! error TS7027: Unreachable code detected.
5486

5587
function f1(x) {
5688
if (x) {
@@ -72,10 +104,16 @@ reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected.
72104
}
73105

74106
module B {
107+
~~~~~~~~~~
75108
for (; ;);
109+
~~~~~~~~~~~~~~
76110
module C {
111+
~~~~~~~~~~~~~~
77112
}
113+
~~~~~
78114
}
115+
~
116+
!!! error TS7027: Unreachable code detected.
79117

80118
function f3() {
81119
do {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [tests/cases/compiler/reachabilityChecks10.ts] ////
2+
3+
=== reachabilityChecks10.ts ===
4+
throw new Error("")
5+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
6+
7+
console.log("1")
8+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
9+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
10+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
11+
12+
console.log("2")
13+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
14+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
15+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
16+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/compiler/reachabilityChecks10.ts] ////
2+
3+
=== reachabilityChecks10.ts ===
4+
throw new Error("")
5+
>new Error("") : Error
6+
>Error : ErrorConstructor
7+
>"" : ""
8+
9+
console.log("1")
10+
>console.log("1") : void
11+
>console.log : (...data: any[]) => void
12+
>console : Console
13+
>log : (...data: any[]) => void
14+
>"1" : "1"
15+
16+
console.log("2")
17+
>console.log("2") : void
18+
>console.log : (...data: any[]) => void
19+
>console : Console
20+
>log : (...data: any[]) => void
21+
>"2" : "2"
22+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//// [tests/cases/compiler/reachabilityChecks9.ts] ////
2+
3+
=== reachabilityChecks9.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/55562
5+
6+
function g(str: string) {
7+
>g : Symbol(g, Decl(reachabilityChecks9.ts, 0, 0))
8+
>str : Symbol(str, Decl(reachabilityChecks9.ts, 2, 11))
9+
10+
switch (str) {
11+
>str : Symbol(str, Decl(reachabilityChecks9.ts, 2, 11))
12+
13+
case "a":
14+
return;
15+
console.log("1");
16+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
17+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
18+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
19+
20+
console.log("2");
21+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
22+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
23+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
24+
25+
case "b":
26+
console.log("3");
27+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
28+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
29+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
30+
}
31+
}
32+
33+
function h(str: string) {
34+
>h : Symbol(h, Decl(reachabilityChecks9.ts, 11, 1))
35+
>str : Symbol(str, Decl(reachabilityChecks9.ts, 13, 11))
36+
37+
switch (str) {
38+
>str : Symbol(str, Decl(reachabilityChecks9.ts, 13, 11))
39+
40+
case "a":
41+
console.log("1");
42+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
43+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
44+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
45+
46+
default:
47+
return;
48+
console.log("2");
49+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
50+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
51+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
52+
53+
console.log("3");
54+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
55+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
56+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
57+
58+
case "b":
59+
console.log("4");
60+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
61+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
62+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
63+
}
64+
}
65+

0 commit comments

Comments
 (0)