Skip to content

Commit 21b5418

Browse files
committed
Add tests
1 parent cafec55 commit 21b5418

File tree

5 files changed

+564
-0
lines changed

5 files changed

+564
-0
lines changed

tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,17 @@ function foo5(bar: "a" | "b"): number {
4040
return 1;
4141
}
4242
}
43+
44+
function foo6(bar: "a", a: boolean, b: boolean): number {
45+
if (a) {
46+
switch (bar) {
47+
case "a": return 1;
48+
}
49+
}
50+
else {
51+
switch (b) {
52+
case true: return -1;
53+
case false: return 0;
54+
}
55+
}
56+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// @strict: true
2+
// @declaration: true
3+
4+
declare function isString(value: unknown): value is string;
5+
declare function isArrayOfStrings(value: unknown): value is string[];
6+
7+
const assert: (value: unknown) => asserts value = value => {}
8+
9+
declare function assertIsString(value: unknown): asserts value is string;
10+
declare function assertIsArrayOfStrings(value: unknown): asserts value is string[];
11+
declare function assertDefined<T>(value: T): asserts value is NonNullable<T>;
12+
13+
function f01(x: unknown) {
14+
if (!!true) {
15+
assert(typeof x === "string");
16+
x.length;
17+
}
18+
if (!!true) {
19+
assert(x instanceof Error);
20+
x.message;
21+
}
22+
if (!!true) {
23+
assert(typeof x === "boolean" || typeof x === "number");
24+
x.toLocaleString;
25+
}
26+
if (!!true) {
27+
assert(isArrayOfStrings(x));
28+
x[0].length;
29+
}
30+
if (!!true) {
31+
assertIsArrayOfStrings(x);
32+
x[0].length;
33+
}
34+
if (!!true) {
35+
assert(x === undefined || typeof x === "string");
36+
x; // string | undefined
37+
assertDefined(x);
38+
x; // string
39+
}
40+
}
41+
42+
function f02(x: string | undefined) {
43+
if (!!true) {
44+
assert(x);
45+
x.length;
46+
}
47+
if (!!true) {
48+
assert(x !== undefined);
49+
x.length;
50+
}
51+
if (!!true) {
52+
assertDefined(x);
53+
x.length;
54+
}
55+
}
56+
57+
function f03(x: string | undefined, assert: (value: unknown) => asserts value) {
58+
assert(x);
59+
x.length;
60+
}
61+
62+
namespace Debug {
63+
export declare function assert(value: unknown, message?: string): asserts value;
64+
export declare function assertDefined<T>(value: T): asserts value is NonNullable<T>;
65+
}
66+
67+
function f10(x: string | undefined) {
68+
if (!!true) {
69+
Debug.assert(x);
70+
x.length;
71+
}
72+
if (!!true) {
73+
Debug.assert(x !== undefined);
74+
x.length;
75+
}
76+
if (!!true) {
77+
Debug.assertDefined(x);
78+
x.length;
79+
}
80+
}
81+
82+
class Test {
83+
assert(value: unknown): asserts value {
84+
if (value) return;
85+
throw new Error();
86+
}
87+
isTest2(): this is Test2 {
88+
return this instanceof Test2;
89+
}
90+
assertIsTest2(): asserts this is Test2 {
91+
if (this instanceof Test2) return;
92+
throw new Error();
93+
}
94+
assertThis(): asserts this {
95+
if (!this) return;
96+
throw new Error();
97+
}
98+
bar() {
99+
this.assertThis();
100+
this;
101+
}
102+
foo(x: unknown) {
103+
this.assert(typeof x === "string");
104+
x.length;
105+
if (this.isTest2()) {
106+
this.z;
107+
}
108+
this.assertIsTest2();
109+
this.z;
110+
}
111+
}
112+
113+
class Test2 extends Test {
114+
z = 0;
115+
}
116+
117+
// Invalid constructs
118+
119+
declare let Q1: new (x: unknown) => x is string;
120+
declare let Q2: new (x: boolean) => asserts x;
121+
declare let Q3: new (x: unknown) => asserts x is string;
122+
123+
declare class Wat {
124+
get p1(): this is string;
125+
set p1(x: this is string);
126+
get p2(): asserts this is string;
127+
set p2(x: asserts this is string);
128+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// @strict: true
2+
// @allowUnreachableCode: false
3+
// @declaration: true
4+
5+
function f1(x: 1 | 2): string {
6+
if (!!true) {
7+
switch (x) {
8+
case 1: return 'a';
9+
case 2: return 'b';
10+
}
11+
x; // Unreachable
12+
}
13+
else {
14+
throw 0;
15+
}
16+
}
17+
18+
function f2(x: 1 | 2) {
19+
let z: number;
20+
switch (x) {
21+
case 1: z = 10; break;
22+
case 2: z = 20; break;
23+
}
24+
z; // Definitely assigned
25+
}
26+
27+
function f3(x: 1 | 2) {
28+
switch (x) {
29+
case 1: return 10;
30+
case 2: return 20;
31+
// Default considered reachable to allow defensive coding
32+
default: throw new Error("Bad input");
33+
}
34+
}
35+
36+
// Repro from #11572
37+
38+
enum E { A, B }
39+
40+
function f(e: E): number {
41+
switch (e) {
42+
case E.A: return 0
43+
case E.B: return 1
44+
}
45+
}
46+
47+
function g(e: E): number {
48+
if (!true)
49+
return -1
50+
else
51+
switch (e) {
52+
case E.A: return 0
53+
case E.B: return 1
54+
}
55+
}
56+
57+
// Repro from #12668
58+
59+
interface Square { kind: "square"; size: number; }
60+
61+
interface Rectangle { kind: "rectangle"; width: number; height: number; }
62+
63+
interface Circle { kind: "circle"; radius: number; }
64+
65+
interface Triangle { kind: "triangle"; side: number; }
66+
67+
type Shape = Square | Rectangle | Circle | Triangle;
68+
69+
function area(s: Shape): number {
70+
let area;
71+
switch (s.kind) {
72+
case "square": area = s.size * s.size; break;
73+
case "rectangle": area = s.width * s.height; break;
74+
case "circle": area = Math.PI * s.radius * s.radius; break;
75+
case "triangle": area = Math.sqrt(3) / 4 * s.side * s.side; break;
76+
}
77+
return area;
78+
}
79+
80+
function areaWrapped(s: Shape): number {
81+
let area;
82+
area = (() => {
83+
switch (s.kind) {
84+
case "square": return s.size * s.size;
85+
case "rectangle": return s.width * s.height;
86+
case "circle": return Math.PI * s.radius * s.radius;
87+
case "triangle": return Math.sqrt(3) / 4 * s.side * s.side;
88+
}
89+
})();
90+
return area;
91+
}
92+
93+
// Repro from #13241
94+
95+
enum MyEnum {
96+
A,
97+
B
98+
}
99+
100+
function thisGivesError(e: MyEnum): string {
101+
let s: string;
102+
switch (e) {
103+
case MyEnum.A: s = "it was A"; break;
104+
case MyEnum.B: s = "it was B"; break;
105+
}
106+
return s;
107+
}
108+
109+
function good1(e: MyEnum): string {
110+
let s: string;
111+
switch (e) {
112+
case MyEnum.A: s = "it was A"; break;
113+
case MyEnum.B: s = "it was B"; break;
114+
default: s = "it was something else"; break;
115+
}
116+
return s;
117+
}
118+
119+
function good2(e: MyEnum): string {
120+
switch (e) {
121+
case MyEnum.A: return "it was A";
122+
case MyEnum.B: return "it was B";
123+
}
124+
}
125+
126+
// Repro from #18362
127+
128+
enum Level {
129+
One,
130+
Two,
131+
}
132+
133+
const doSomethingWithLevel = (level: Level) => {
134+
let next: Level;
135+
switch (level) {
136+
case Level.One:
137+
next = Level.Two;
138+
break;
139+
case Level.Two:
140+
next = Level.One;
141+
break;
142+
}
143+
return next;
144+
};
145+
146+
// Repro from #20409
147+
148+
interface Square2 {
149+
kind: "square";
150+
size: number;
151+
}
152+
153+
interface Circle2 {
154+
kind: "circle";
155+
radius: number;
156+
}
157+
158+
type Shape2 = Square2 | Circle2;
159+
160+
function withDefault(s1: Shape2, s2: Shape2): string {
161+
switch (s1.kind) {
162+
case "square":
163+
return "1";
164+
case "circle":
165+
switch (s2.kind) {
166+
case "square":
167+
return "2";
168+
case "circle":
169+
return "3";
170+
default:
171+
return "never";
172+
}
173+
}
174+
}
175+
176+
function withoutDefault(s1: Shape2, s2: Shape2): string {
177+
switch (s1.kind) {
178+
case "square":
179+
return "1";
180+
case "circle":
181+
switch (s2.kind) {
182+
case "square":
183+
return "2";
184+
case "circle":
185+
return "3";
186+
}
187+
}
188+
}
189+
190+
// Repro from #20823
191+
192+
function test4(value: 1 | 2) {
193+
let x: string;
194+
switch (value) {
195+
case 1: x = "one"; break;
196+
case 2: x = "two"; break;
197+
}
198+
return x;
199+
}

0 commit comments

Comments
 (0)