Skip to content

Commit f3e4ba4

Browse files
committed
switch typeof any could be checked for unreachable
1 parent 9ac7412 commit f3e4ba4

6 files changed

+140
-6
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ namespace ts {
131131
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
132132
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
133133
EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull),
134+
AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined,
134135
EmptyObjectFacts = All,
135136
}
136137

@@ -28565,6 +28566,10 @@ namespace ts {
2856528566
// notEqualFacts states that the type of the switched value is not equal to every type in the switch.
2856628567
const notEqualFacts = getFactsFromTypeofSwitch(0, 0, witnesses, /*hasDefault*/ true);
2856728568
const type = getBaseConstraintOfType(operandType) || operandType;
28569+
// Take any as a specail condition. Maybe we could change type to a union containing all primitive types.
28570+
if (type.flags = TypeFlags.Any) {
28571+
return (TypeFacts.AllTypeofNE & notEqualFacts) === TypeFacts.AllTypeofNE;
28572+
}
2856828573
return !!(filterType(type, t => (getTypeFacts(t) & notEqualFacts) === notEqualFacts).flags & TypeFlags.Never);
2856928574
}
2857028575
const type = getTypeOfExpression(node.expression);
@@ -30345,12 +30350,12 @@ namespace ts {
3034530350
}
3034630351
// If a type has been cached for the node, return it.
3034730352
// Note: this is not only cache, without this, some test case would always runs, such as binaryArithmeticControlFlowGraphNotTooLarge.
30348-
if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
30349-
const cachedType = flowTypeCache[getNodeId(node)];
30350-
if (cachedType) {
30351-
return cachedType;
30352-
}
30353-
}
30353+
// if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
30354+
// const cachedType = flowTypeCache[getNodeId(node)];
30355+
// if (cachedType) {
30356+
// return cachedType;
30357+
// }
30358+
// }
3035430359
const startInvocationCount = flowInvocationCount;
3035530360
const type = checkExpression(node);
3035630361
// If control flow analysis was required to determine the type, it is worth caching.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
tests/cases/compiler/unreachable.ts(12,5): error TS7027: Unreachable code detected.
2+
3+
4+
==== tests/cases/compiler/unreachable.ts (1 errors) ====
5+
const unreachable = (x: any): number => {
6+
switch (typeof x) {
7+
case 'string': return 0
8+
case 'number': return 0
9+
case 'bigint': return 0
10+
case 'boolean': return 0
11+
case 'symbol': return 0
12+
case 'undefined': return 0
13+
case 'object': return 0
14+
case 'function': return 0
15+
}
16+
x;
17+
~~
18+
!!! error TS7027: Unreachable code detected.
19+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [unreachable.ts]
2+
const unreachable = (x: any): number => {
3+
switch (typeof x) {
4+
case 'string': return 0
5+
case 'number': return 0
6+
case 'bigint': return 0
7+
case 'boolean': return 0
8+
case 'symbol': return 0
9+
case 'undefined': return 0
10+
case 'object': return 0
11+
case 'function': return 0
12+
}
13+
x;
14+
}
15+
16+
//// [unreachable.js]
17+
var unreachable = function (x) {
18+
switch (typeof x) {
19+
case 'string': return 0;
20+
case 'number': return 0;
21+
case 'bigint': return 0;
22+
case 'boolean': return 0;
23+
case 'symbol': return 0;
24+
case 'undefined': return 0;
25+
case 'object': return 0;
26+
case 'function': return 0;
27+
}
28+
x;
29+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/compiler/unreachable.ts ===
2+
const unreachable = (x: any): number => {
3+
>unreachable : Symbol(unreachable, Decl(unreachable.ts, 0, 5))
4+
>x : Symbol(x, Decl(unreachable.ts, 0, 21))
5+
6+
switch (typeof x) {
7+
>x : Symbol(x, Decl(unreachable.ts, 0, 21))
8+
9+
case 'string': return 0
10+
case 'number': return 0
11+
case 'bigint': return 0
12+
case 'boolean': return 0
13+
case 'symbol': return 0
14+
case 'undefined': return 0
15+
case 'object': return 0
16+
case 'function': return 0
17+
}
18+
x;
19+
>x : Symbol(x, Decl(unreachable.ts, 0, 21))
20+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/unreachable.ts ===
2+
const unreachable = (x: any): number => {
3+
>unreachable : (x: any) => number
4+
>(x: any): number => { switch (typeof x) { case 'string': return 0 case 'number': return 0 case 'bigint': return 0 case 'boolean': return 0 case 'symbol': return 0 case 'undefined': return 0 case 'object': return 0 case 'function': return 0 } x;} : (x: any) => number
5+
>x : any
6+
7+
switch (typeof x) {
8+
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
9+
>x : any
10+
11+
case 'string': return 0
12+
>'string' : "string"
13+
>0 : 0
14+
15+
case 'number': return 0
16+
>'number' : "number"
17+
>0 : 0
18+
19+
case 'bigint': return 0
20+
>'bigint' : "bigint"
21+
>0 : 0
22+
23+
case 'boolean': return 0
24+
>'boolean' : "boolean"
25+
>0 : 0
26+
27+
case 'symbol': return 0
28+
>'symbol' : "symbol"
29+
>0 : 0
30+
31+
case 'undefined': return 0
32+
>'undefined' : "undefined"
33+
>0 : 0
34+
35+
case 'object': return 0
36+
>'object' : "object"
37+
>0 : 0
38+
39+
case 'function': return 0
40+
>'function' : "function"
41+
>0 : 0
42+
}
43+
x;
44+
>x : any
45+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @Filename: unreachable.ts
2+
// @outDir: out
3+
// @allowUnreachableCode: false
4+
const unreachable = (x: any): number => {
5+
switch (typeof x) {
6+
case 'string': return 0
7+
case 'number': return 0
8+
case 'bigint': return 0
9+
case 'boolean': return 0
10+
case 'symbol': return 0
11+
case 'undefined': return 0
12+
case 'object': return 0
13+
case 'function': return 0
14+
}
15+
x;
16+
}

0 commit comments

Comments
 (0)