Merge pull request #25822 from Kingwl/rechabilityImprove

improve enum rechability check
This commit is contained in:
Ryan Cavanaugh 2018-09-05 11:46:07 -07:00 committed by GitHub
commit 4975dc85b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 244 additions and 27 deletions

View file

@ -2802,9 +2802,7 @@ namespace ts {
// report error on class declarations
node.kind === SyntaxKind.ClassDeclaration ||
// report error on instantiated modules or const-enums only modules if preserveConstEnums is set
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node)) ||
// report error on regular enums and const enums if preserveConstEnums is set
(isEnumDeclaration(node) && (!isEnumConst(node) || options.preserveConstEnums));
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node));
if (reportError) {
currentFlow = reportedUnreachableFlow;
@ -2849,7 +2847,7 @@ namespace ts {
// As opposed to a pure declaration like an `interface`
function isExecutableStatement(s: Statement): boolean {
// Don't remove statements that can validly be used before they appear.
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) &&
// `var x;` may declare a variable used above
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
}

View file

@ -1703,6 +1703,9 @@ namespace ts {
}
else {
Debug.assert(!!(result.flags & SymbolFlags.ConstEnum));
if (compilerOptions.preserveConstEnums) {
diagnosticMessage = error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationName);
}
}
if (diagnosticMessage) {
@ -22981,6 +22984,12 @@ namespace ts {
}
}
const enum DeclarationSpaces {
None = 0,
ExportValue = 1 << 0,
ExportType = 1 << 1,
ExportNamespace = 1 << 2,
}
function checkExportsOnMergedDeclarations(node: Node): void {
if (!produceDiagnostics) {
return;
@ -23045,12 +23054,6 @@ namespace ts {
}
}
const enum DeclarationSpaces {
None = 0,
ExportValue = 1 << 0,
ExportType = 1 << 1,
ExportNamespace = 1 << 2,
}
function getDeclarationSpaces(decl: Declaration): DeclarationSpaces {
let d = decl as Node;
switch (d.kind) {

View file

@ -0,0 +1,16 @@
tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts(2,12): error TS2450: Enum 'E' used before its declaration.
==== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts (1 errors) ====
function foo1() {
return E.A
~
!!! error TS2450: Enum 'E' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts:3:10: 'E' is declared here.
enum E { A }
}
function foo2() {
return E.A
const enum E { A }
}

View file

@ -0,0 +1,22 @@
//// [blockScopedEnumVariablesUseBeforeDef.ts]
function foo1() {
return E.A
enum E { A }
}
function foo2() {
return E.A
const enum E { A }
}
//// [blockScopedEnumVariablesUseBeforeDef.js]
function foo1() {
return E.A;
var E;
(function (E) {
E[E["A"] = 0] = "A";
})(E || (E = {}));
}
function foo2() {
return 0 /* A */;
}

View file

@ -0,0 +1,26 @@
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts ===
function foo1() {
>foo1 : Symbol(foo1, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 0, 0))
return E.A
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 2, 12))
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 1, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 2, 12))
enum E { A }
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 1, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 2, 12))
}
function foo2() {
>foo2 : Symbol(foo2, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 3, 1))
return E.A
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 7, 18))
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 6, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 7, 18))
const enum E { A }
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 6, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef.ts, 7, 18))
}

View file

@ -0,0 +1,26 @@
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef.ts ===
function foo1() {
>foo1 : () => E
return E.A
>E.A : E
>E : typeof E
>A : E
enum E { A }
>E : E
>A : E
}
function foo2() {
>foo2 : () => E
return E.A
>E.A : E
>E : typeof E
>A : E
const enum E { A }
>E : E
>A : E
}

View file

@ -0,0 +1,20 @@
tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts(2,12): error TS2450: Enum 'E' used before its declaration.
tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts(7,12): error TS2449: Class 'E' used before its declaration.
==== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts (2 errors) ====
function foo1() {
return E.A
~
!!! error TS2450: Enum 'E' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts:3:10: 'E' is declared here.
enum E { A }
}
function foo2() {
return E.A
~
!!! error TS2449: Class 'E' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts:8:16: 'E' is declared here.
const enum E { A }
}

View file

@ -0,0 +1,26 @@
//// [blockScopedEnumVariablesUseBeforeDef_preserve.ts]
function foo1() {
return E.A
enum E { A }
}
function foo2() {
return E.A
const enum E { A }
}
//// [blockScopedEnumVariablesUseBeforeDef_preserve.js]
function foo1() {
return E.A;
var E;
(function (E) {
E[E["A"] = 0] = "A";
})(E || (E = {}));
}
function foo2() {
return 0 /* A */;
var E;
(function (E) {
E[E["A"] = 0] = "A";
})(E || (E = {}));
}

View file

@ -0,0 +1,26 @@
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts ===
function foo1() {
>foo1 : Symbol(foo1, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 0, 0))
return E.A
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 2, 12))
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 1, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 2, 12))
enum E { A }
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 1, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 2, 12))
}
function foo2() {
>foo2 : Symbol(foo2, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 3, 1))
return E.A
>E.A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 7, 18))
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 6, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 7, 18))
const enum E { A }
>E : Symbol(E, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 6, 14))
>A : Symbol(E.A, Decl(blockScopedEnumVariablesUseBeforeDef_preserve.ts, 7, 18))
}

View file

@ -0,0 +1,26 @@
=== tests/cases/compiler/blockScopedEnumVariablesUseBeforeDef_preserve.ts ===
function foo1() {
>foo1 : () => E
return E.A
>E.A : E
>E : typeof E
>A : E
enum E { A }
>E : E
>A : E
}
function foo2() {
>foo2 : () => E
return E.A
>E.A : E
>E : typeof E
>A : E
const enum E { A }
>E : E
>A : E
}

View file

@ -119,4 +119,5 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:102:9: 'x' is declared here.
}
let x
}
}

View file

@ -101,7 +101,8 @@ function foo14() {
a: x
}
let x
}
}
//// [blockScopedVariablesUseBeforeDef.js]
function foo0() {

View file

@ -212,3 +212,4 @@ function foo14() {
let x
>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 101, 7))
}

View file

@ -224,3 +224,4 @@ function foo14() {
let x
>x : any
}

View file

@ -3,11 +3,9 @@ tests/cases/compiler/reachabilityChecks1.ts(6,5): error TS7027: Unreachable code
tests/cases/compiler/reachabilityChecks1.ts(18,5): error TS7027: Unreachable code detected.
tests/cases/compiler/reachabilityChecks1.ts(30,5): error TS7027: Unreachable code detected.
tests/cases/compiler/reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected.
tests/cases/compiler/reachabilityChecks1.ts(60,5): error TS7027: Unreachable code detected.
tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable code detected.
==== tests/cases/compiler/reachabilityChecks1.ts (7 errors) ====
==== tests/cases/compiler/reachabilityChecks1.ts (5 errors) ====
while (true);
var x = 1;
~~~~~~~~~~
@ -83,12 +81,8 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
do {
} while (true);
enum E {
~~~~~~~~
X = 1
~~~~~~~~~~~~~
}
~~~~~
!!! error TS7027: Unreachable code detected.
}
function f4() {
@ -96,12 +90,8 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
throw new Error();
}
const enum E {
~~~~~~~~~~~~~~
X = 1
~~~~~~~~~~~~~
}
~~~~~
!!! error TS7027: Unreachable code detected.
}

View file

@ -0,0 +1,10 @@
// @target: ES5
function foo1() {
return E.A
enum E { A }
}
function foo2() {
return E.A
const enum E { A }
}

View file

@ -0,0 +1,12 @@
// @target: ES5
// @preserveConstEnums: true
function foo1() {
return E.A
enum E { A }
}
function foo2() {
return E.A
const enum E { A }
}

View file

@ -101,4 +101,4 @@ function foo14() {
a: x
}
let x
}
}

View file

@ -3,12 +3,12 @@
////function f() {
//// return f();
//// [|return 1;|]
//// function f() {}
//// function f(a?: EE) { return a; }
//// [|return 2;|]
//// type T = number;
//// interface I {}
//// const enum E {}
//// [|enum E {}|]
//// enum EE {}
//// namespace N { export type T = number; }
//// [|namespace N { export const x: T = 0; }|]
//// var x: I;
@ -29,11 +29,23 @@ verify.codeFixAll({
newFileContent:
`function f() {
return f();
function f() {}
function f(a?: EE) { return a; }
type T = number;
interface I {}
const enum E {}
enum EE {}
namespace N { export type T = number; }
var x: I;
}`,
});
function f() {
return f();
function f(a?: EE) { return a; }
type T = number;
interface I {}
const enum E {}
enum EE {}
namespace N { export type T = number; }
var x: I;
}