Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report unreachable on enums #58380

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3785,6 +3785,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
(isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) ||
// report error on class declarations
node.kind === SyntaxKind.ClassDeclaration ||
(node.kind === SyntaxKind.EnumDeclaration && (!isEnumConst(node as EnumDeclaration) || shouldPreserveConstEnums(options))) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(node.kind === SyntaxKind.EnumDeclaration && (!isEnumConst(node as EnumDeclaration) || shouldPreserveConstEnums(options))) ||
// report errors on enums with preserved emit
(node.kind === SyntaxKind.EnumDeclaration && (!isEnumConst(node as EnumDeclaration) || shouldPreserveConstEnums(options))) ||

// report error on instantiated modules or const-enums only modules if preserveConstEnums is set
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration));

Expand Down
12 changes: 11 additions & 1 deletion tests/baselines/reference/reachabilityChecks1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ reachabilityChecks1.ts(6,5): error TS7027: Unreachable code detected.
reachabilityChecks1.ts(18,5): error TS7027: Unreachable code detected.
reachabilityChecks1.ts(30,5): error TS7027: Unreachable code detected.
reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected.
reachabilityChecks1.ts(60,5): error TS7027: Unreachable code detected.
reachabilityChecks1.ts(69,5): error TS7027: Unreachable code detected.


==== reachabilityChecks1.ts (5 errors) ====
==== reachabilityChecks1.ts (7 errors) ====
while (true);
var x = 1;
~~~~~~~~~~
Expand Down Expand Up @@ -81,17 +83,25 @@ reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected.
do {
} while (true);
enum E {
~~~~~~~~
X = 1
~~~~~~~~~~~~~
}
~~~~~
!!! error TS7027: Unreachable code detected.
}

function f4() {
if (true) {
throw new Error();
}
const enum E {
~~~~~~~~~~~~~~
X = 1
~~~~~~~~~~~~~
}
~~~~~
!!! error TS7027: Unreachable code detected.
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
unreachableEnum.ts(4,17): error TS2450: Enum 'EnumA' used before its declaration.
unreachableEnum.ts(14,5): error TS7027: Unreachable code detected.
unreachableEnum.ts(21,17): error TS2450: Enum 'EnumA' used before its declaration.
unreachableEnum.ts(29,5): error TS7027: Unreachable code detected.


==== unreachableEnum.ts (4 errors) ====
function func1() {
aFunc();

console.log(EnumA.Value);
~~~~~
!!! error TS2450: Enum 'EnumA' used before its declaration.
!!! related TS2728 unreachableEnum.ts:14:10: 'EnumA' is declared here.
console.log(EnumB.Value);

return;

function aFunc() {
console.log(EnumA.Value);
console.log(EnumB.Value);
}

enum EnumA { Value }
~~~~~~~~~~~~~~~~~~~~
!!! error TS7027: Unreachable code detected.
const enum EnumB { Value }
}

function func2() {
aFunc();

console.log(EnumA.Value);
~~~~~
!!! error TS2450: Enum 'EnumA' used before its declaration.
!!! related TS2728 unreachableEnum.ts:29:10: 'EnumA' is declared here.

return;

function aFunc() {
console.log(EnumA.Value);
}

enum EnumA { Value }
~~~~~~~~~~~~~~~~~~~~
!!! error TS7027: Unreachable code detected.
}

function func3() {
aFunc();

console.log(EnumB.Value);

return;

function aFunc() {
console.log(EnumB.Value);
}

const enum EnumB { Value }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//// [tests/cases/compiler/unreachableEnum.ts] ////

//// [unreachableEnum.ts]
function func1() {
aFunc();

console.log(EnumA.Value);
console.log(EnumB.Value);

return;

function aFunc() {
console.log(EnumA.Value);
console.log(EnumB.Value);
}

enum EnumA { Value }
const enum EnumB { Value }
}

function func2() {
aFunc();

console.log(EnumA.Value);

return;

function aFunc() {
console.log(EnumA.Value);
}

enum EnumA { Value }
}

function func3() {
aFunc();

console.log(EnumB.Value);

return;

function aFunc() {
console.log(EnumB.Value);
}

const enum EnumB { Value }
}

//// [unreachableEnum.js]
"use strict";
function func1() {
aFunc();
console.log(EnumA.Value);
console.log(0 /* EnumB.Value */);
return;
function aFunc() {
console.log(EnumA.Value);
console.log(0 /* EnumB.Value */);
}
var EnumA;
(function (EnumA) {
EnumA[EnumA["Value"] = 0] = "Value";
})(EnumA || (EnumA = {}));
}
function func2() {
aFunc();
console.log(EnumA.Value);
return;
function aFunc() {
console.log(EnumA.Value);
}
var EnumA;
(function (EnumA) {
EnumA[EnumA["Value"] = 0] = "Value";
})(EnumA || (EnumA = {}));
}
function func3() {
aFunc();
console.log(0 /* EnumB.Value */);
return;
function aFunc() {
console.log(0 /* EnumB.Value */);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//// [tests/cases/compiler/unreachableEnum.ts] ////

=== unreachableEnum.ts ===
function func1() {
>func1 : Symbol(func1, Decl(unreachableEnum.ts, 0, 0))

aFunc();
>aFunc : Symbol(aFunc, Decl(unreachableEnum.ts, 6, 11))

console.log(EnumA.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumA.Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 13, 16))
>EnumA : Symbol(EnumA, Decl(unreachableEnum.ts, 11, 5))
>Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 13, 16))

console.log(EnumB.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumB.Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 14, 22))
>EnumB : Symbol(EnumB, Decl(unreachableEnum.ts, 13, 24))
>Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 14, 22))

return;

function aFunc() {
>aFunc : Symbol(aFunc, Decl(unreachableEnum.ts, 6, 11))

console.log(EnumA.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumA.Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 13, 16))
>EnumA : Symbol(EnumA, Decl(unreachableEnum.ts, 11, 5))
>Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 13, 16))

console.log(EnumB.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumB.Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 14, 22))
>EnumB : Symbol(EnumB, Decl(unreachableEnum.ts, 13, 24))
>Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 14, 22))
}

enum EnumA { Value }
>EnumA : Symbol(EnumA, Decl(unreachableEnum.ts, 11, 5))
>Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 13, 16))

const enum EnumB { Value }
>EnumB : Symbol(EnumB, Decl(unreachableEnum.ts, 13, 24))
>Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 14, 22))
}

function func2() {
>func2 : Symbol(func2, Decl(unreachableEnum.ts, 15, 1))

aFunc();
>aFunc : Symbol(aFunc, Decl(unreachableEnum.ts, 22, 11))

console.log(EnumA.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumA.Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 28, 16))
>EnumA : Symbol(EnumA, Decl(unreachableEnum.ts, 26, 5))
>Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 28, 16))

return;

function aFunc() {
>aFunc : Symbol(aFunc, Decl(unreachableEnum.ts, 22, 11))

console.log(EnumA.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumA.Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 28, 16))
>EnumA : Symbol(EnumA, Decl(unreachableEnum.ts, 26, 5))
>Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 28, 16))
}

enum EnumA { Value }
>EnumA : Symbol(EnumA, Decl(unreachableEnum.ts, 26, 5))
>Value : Symbol(EnumA.Value, Decl(unreachableEnum.ts, 28, 16))
}

function func3() {
>func3 : Symbol(func3, Decl(unreachableEnum.ts, 29, 1))

aFunc();
>aFunc : Symbol(aFunc, Decl(unreachableEnum.ts, 36, 11))

console.log(EnumB.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumB.Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 42, 22))
>EnumB : Symbol(EnumB, Decl(unreachableEnum.ts, 40, 5))
>Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 42, 22))

return;

function aFunc() {
>aFunc : Symbol(aFunc, Decl(unreachableEnum.ts, 36, 11))

console.log(EnumB.Value);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>EnumB.Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 42, 22))
>EnumB : Symbol(EnumB, Decl(unreachableEnum.ts, 40, 5))
>Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 42, 22))
}

const enum EnumB { Value }
>EnumB : Symbol(EnumB, Decl(unreachableEnum.ts, 40, 5))
>Value : Symbol(EnumB.Value, Decl(unreachableEnum.ts, 42, 22))
}