Skip to content

Commit 4975dc8

Browse files
Merge pull request #25822 from Kingwl/rechabilityImprove
improve enum rechability check
2 parents 1eb3082 + 1c522a6 commit 4975dc8

19 files changed

+244
-27
lines changed

src/compiler/binder.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,9 +2802,7 @@ namespace ts {
28022802
// report error on class declarations
28032803
node.kind === SyntaxKind.ClassDeclaration ||
28042804
// report error on instantiated modules or const-enums only modules if preserveConstEnums is set
2805-
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node)) ||
2806-
// report error on regular enums and const enums if preserveConstEnums is set
2807-
(isEnumDeclaration(node) && (!isEnumConst(node) || options.preserveConstEnums));
2805+
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node));
28082806

28092807
if (reportError) {
28102808
currentFlow = reportedUnreachableFlow;
@@ -2849,7 +2847,7 @@ namespace ts {
28492847
// As opposed to a pure declaration like an `interface`
28502848
function isExecutableStatement(s: Statement): boolean {
28512849
// Don't remove statements that can validly be used before they appear.
2852-
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
2850+
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) &&
28532851
// `var x;` may declare a variable used above
28542852
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
28552853
}

src/compiler/checker.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,9 @@ namespace ts {
17031703
}
17041704
else {
17051705
Debug.assert(!!(result.flags & SymbolFlags.ConstEnum));
1706+
if (compilerOptions.preserveConstEnums) {
1707+
diagnosticMessage = error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationName);
1708+
}
17061709
}
17071710

17081711
if (diagnosticMessage) {
@@ -22981,6 +22984,12 @@ namespace ts {
2298122984
}
2298222985
}
2298322986

22987+
const enum DeclarationSpaces {
22988+
None = 0,
22989+
ExportValue = 1 << 0,
22990+
ExportType = 1 << 1,
22991+
ExportNamespace = 1 << 2,
22992+
}
2298422993
function checkExportsOnMergedDeclarations(node: Node): void {
2298522994
if (!produceDiagnostics) {
2298622995
return;
@@ -23045,12 +23054,6 @@ namespace ts {
2304523054
}
2304623055
}
2304723056

23048-
const enum DeclarationSpaces {
23049-
None = 0,
23050-
ExportValue = 1 << 0,
23051-
ExportType = 1 << 1,
23052-
ExportNamespace = 1 << 2,
23053-
}
2305423057
function getDeclarationSpaces(decl: Declaration): DeclarationSpaces {
2305523058
let d = decl as Node;
2305623059
switch (d.kind) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts(2,12): error TS2450: Enum 'E' used before its declaration.
2+
3+
4+
==== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts (1 errors) ====
5+
function foo1() {
6+
return E.A
7+
~
8+
!!! error TS2450: Enum 'E' used before its declaration.
9+
!!! related TS2728 tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts:3:10: 'E' is declared here.
10+
enum E { A }
11+
}
12+
13+
function foo2() {
14+
return E.A
15+
const enum E { A }
16+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [blockScopedEnumVariablesUseBeforeDef.ts]
2+
function foo1() {
3+
return E.A
4+
enum E { A }
5+
}
6+
7+
function foo2() {
8+
return E.A
9+
const enum E { A }
10+
}
11+
12+
//// [blockScopedEnumVariablesUseBeforeDef.js]
13+
function foo1() {
14+
return E.A;
15+
var E;
16+
(function (E) {
17+
E[E["A"] = 0] = "A";
18+
})(E || (E = {}));
19+
}
20+
function foo2() {
21+
return 0 /* A */;
22+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts ===
2+
function foo1() {
3+
>foo1 : Symbol(foo1, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 0, 0))
4+
5+
return E.A
6+
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 2, 12))
7+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 1, 14))
8+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 2, 12))
9+
10+
enum E { A }
11+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 1, 14))
12+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 2, 12))
13+
}
14+
15+
function foo2() {
16+
>foo2 : Symbol(foo2, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 3, 1))
17+
18+
return E.A
19+
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 7, 18))
20+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 6, 14))
21+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 7, 18))
22+
23+
const enum E { A }
24+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 6, 14))
25+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 7, 18))
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts ===
2+
function foo1() {
3+
>foo1 : () => E
4+
5+
return E.A
6+
>E.A : E
7+
>E : typeof E
8+
>A : E
9+
10+
enum E { A }
11+
>E : E
12+
>A : E
13+
}
14+
15+
function foo2() {
16+
>foo2 : () => E
17+
18+
return E.A
19+
>E.A : E
20+
>E : typeof E
21+
>A : E
22+
23+
const enum E { A }
24+
>E : E
25+
>A : E
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts(2,12): error TS2450: Enum 'E' used before its declaration.
2+
tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts(7,12): error TS2449: Class 'E' used before its declaration.
3+
4+
5+
==== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts (2 errors) ====
6+
function foo1() {
7+
return E.A
8+
~
9+
!!! error TS2450: Enum 'E' used before its declaration.
10+
!!! related TS2728 tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts:3:10: 'E' is declared here.
11+
enum E { A }
12+
}
13+
14+
function foo2() {
15+
return E.A
16+
~
17+
!!! error TS2449: Class 'E' used before its declaration.
18+
!!! related TS2728 tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts:8:16: 'E' is declared here.
19+
const enum E { A }
20+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [blockScopedEnumVariablesUseBeforeDef_preserve.ts]
2+
function foo1() {
3+
return E.A
4+
enum E { A }
5+
}
6+
7+
function foo2() {
8+
return E.A
9+
const enum E { A }
10+
}
11+
12+
//// [blockScopedEnumVariablesUseBeforeDef_preserve.js]
13+
function foo1() {
14+
return E.A;
15+
var E;
16+
(function (E) {
17+
E[E["A"] = 0] = "A";
18+
})(E || (E = {}));
19+
}
20+
function foo2() {
21+
return 0 /* A */;
22+
var E;
23+
(function (E) {
24+
E[E["A"] = 0] = "A";
25+
})(E || (E = {}));
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts ===
2+
function foo1() {
3+
>foo1 : Symbol(foo1, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 0, 0))
4+
5+
return E.A
6+
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 2, 12))
7+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 1, 14))
8+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 2, 12))
9+
10+
enum E { A }
11+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 1, 14))
12+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 2, 12))
13+
}
14+
15+
function foo2() {
16+
>foo2 : Symbol(foo2, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 3, 1))
17+
18+
return E.A
19+
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 7, 18))
20+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 6, 14))
21+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 7, 18))
22+
23+
const enum E { A }
24+
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 6, 14))
25+
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 7, 18))
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts ===
2+
function foo1() {
3+
>foo1 : () => E
4+
5+
return E.A
6+
>E.A : E
7+
>E : typeof E
8+
>A : E
9+
10+
enum E { A }
11+
>E : E
12+
>A : E
13+
}
14+
15+
function foo2() {
16+
>foo2 : () => E
17+
18+
return E.A
19+
>E.A : E
20+
>E : typeof E
21+
>A : E
22+
23+
const enum E { A }
24+
>E : E
25+
>A : E
26+
}

tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,5 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
119119
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:102:9: 'x' is declared here.
120120
}
121121
let x
122-
}
122+
}
123+

tests/baselines/reference/blockScopedVariablesUseBeforeDef.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ function foo14() {
101101
a: x
102102
}
103103
let x
104-
}
104+
}
105+
105106

106107
//// [blockScopedVariablesUseBeforeDef.js]
107108
function foo0() {

tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,4 @@ function foo14() {
212212
let x
213213
>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 101, 7))
214214
}
215+

tests/baselines/reference/blockScopedVariablesUseBeforeDef.types

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,4 @@ function foo14() {
224224
let x
225225
>x : any
226226
}
227+

tests/baselines/reference/reachabilityChecks1.errors.txt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ tests/cases/compiler/reachabilityChecks1.ts(6,5): error TS7027: Unreachable code
33
tests/cases/compiler/reachabilityChecks1.ts(18,5): error TS7027: Unreachable code detected.
44
tests/cases/compiler/reachabilityChecks1.ts(30,5): error TS7027: Unreachable code detected.
55
tests/cases/compiler/reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected.
6-
tests/cases/compiler/reachabilityChecks1.ts(60,5): error TS7027: Unreachable code detected.
7-
tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable code detected.
86

97

10-
==== tests/cases/compiler/reachabilityChecks1.ts (7 errors) ====
8+
==== tests/cases/compiler/reachabilityChecks1.ts (5 errors) ====
119
while (true);
1210
var x = 1;
1311
~~~~~~~~~~
@@ -83,25 +81,17 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
8381
do {
8482
} while (true);
8583
enum E {
86-
~~~~~~~~
8784
X = 1
88-
~~~~~~~~~~~~~
8985
}
90-
~~~~~
91-
!!! error TS7027: Unreachable code detected.
9286
}
9387

9488
function f4() {
9589
if (true) {
9690
throw new Error();
9791
}
9892
const enum E {
99-
~~~~~~~~~~~~~~
10093
X = 1
101-
~~~~~~~~~~~~~
10294
}
103-
~~~~~
104-
!!! error TS7027: Unreachable code detected.
10595
}
10696

10797

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @target: ES5
2+
function foo1() {
3+
return E.A
4+
enum E { A }
5+
}
6+
7+
function foo2() {
8+
return E.A
9+
const enum E { A }
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @target: ES5
2+
// @preserveConstEnums: true
3+
4+
function foo1() {
5+
return E.A
6+
enum E { A }
7+
}
8+
9+
function foo2() {
10+
return E.A
11+
const enum E { A }
12+
}

tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,4 @@ function foo14() {
101101
a: x
102102
}
103103
let x
104-
}
104+
}

tests/cases/fourslash/codeFixUnreachableCode.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
////function f() {
44
//// return f();
55
//// [|return 1;|]
6-
//// function f() {}
6+
//// function f(a?: EE) { return a; }
77
//// [|return 2;|]
88
//// type T = number;
99
//// interface I {}
1010
//// const enum E {}
11-
//// [|enum E {}|]
11+
//// enum EE {}
1212
//// namespace N { export type T = number; }
1313
//// [|namespace N { export const x: T = 0; }|]
1414
//// var x: I;
@@ -29,11 +29,23 @@ verify.codeFixAll({
2929
newFileContent:
3030
`function f() {
3131
return f();
32-
function f() {}
32+
function f(a?: EE) { return a; }
3333
type T = number;
3434
interface I {}
3535
const enum E {}
36+
enum EE {}
3637
namespace N { export type T = number; }
3738
var x: I;
3839
}`,
3940
});
41+
42+
function f() {
43+
return f();
44+
function f(a?: EE) { return a; }
45+
type T = number;
46+
interface I {}
47+
const enum E {}
48+
enum EE {}
49+
namespace N { export type T = number; }
50+
var x: I;
51+
}

0 commit comments

Comments
 (0)