Skip to content

Commit 38db7ae

Browse files
authored
Properly analyze switch statement bypass control flow (microsoft#35087)
* Properly analyze switch statement bypass control flow * Add regression test * Accept new baselines
1 parent aa39080 commit 38db7ae

File tree

6 files changed

+147
-2
lines changed

6 files changed

+147
-2
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19333,7 +19333,7 @@ namespace ts {
1933319333
}
1933419334
}
1933519335
if (bypassFlow) {
19336-
const flowType = getTypeAtFlowNode(bypassFlow.antecedent);
19336+
const flowType = getTypeAtFlowNode(bypassFlow);
1933719337
const type = getTypeFromFlowType(flowType);
1933819338
// If the bypass flow contributes a type we haven't seen yet and the switch statement
1933919339
// isn't exhaustive, process the bypass flow type. Since exhaustiveness checks increase

tests/baselines/reference/exhaustiveSwitchStatements1.errors.txt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error TS7027: Unreachable code detected.
2+
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error TS2367: This condition will always return 'false' since the types '"a" | "b"' and '"c"' have no overlap.
23

34

4-
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (1 errors) ====
5+
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (2 errors) ====
56
function f1(x: 1 | 2): string {
67
if (!!true) {
78
switch (x) {
@@ -225,4 +226,22 @@ tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error T
225226
}
226227
}
227228
}
229+
230+
// Repro from #35070
231+
232+
type O = {
233+
a: number,
234+
b: number
235+
};
236+
type K = keyof O | 'c';
237+
function ff(o: O, k: K) {
238+
switch(k) {
239+
case 'c':
240+
k = 'a';
241+
}
242+
k === 'c'; // Error
243+
~~~~~~~~~
244+
!!! error TS2367: This condition will always return 'false' since the types '"a" | "b"' and '"c"' have no overlap.
245+
return o[k];
246+
}
228247

tests/baselines/reference/exhaustiveSwitchStatements1.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,22 @@ function foo() {
220220
}
221221
}
222222
}
223+
224+
// Repro from #35070
225+
226+
type O = {
227+
a: number,
228+
b: number
229+
};
230+
type K = keyof O | 'c';
231+
function ff(o: O, k: K) {
232+
switch(k) {
233+
case 'c':
234+
k = 'a';
235+
}
236+
k === 'c'; // Error
237+
return o[k];
238+
}
223239

224240

225241
//// [exhaustiveSwitchStatements1.js]
@@ -429,6 +445,14 @@ function foo() {
429445
}
430446
}
431447
}
448+
function ff(o, k) {
449+
switch (k) {
450+
case 'c':
451+
k = 'a';
452+
}
453+
k === 'c'; // Error
454+
return o[k];
455+
}
432456

433457

434458
//// [exhaustiveSwitchStatements1.d.ts]
@@ -494,3 +518,9 @@ declare const zoo: {
494518
} | undefined;
495519
declare function expression(): Animal;
496520
declare function foo(): void;
521+
declare type O = {
522+
a: number;
523+
b: number;
524+
};
525+
declare type K = keyof O | 'c';
526+
declare function ff(o: O, k: K): number;

tests/baselines/reference/exhaustiveSwitchStatements1.symbols

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,3 +565,41 @@ function foo() {
565565
}
566566
}
567567

568+
// Repro from #35070
569+
570+
type O = {
571+
>O : Symbol(O, Decl(exhaustiveSwitchStatements1.ts, 220, 1))
572+
573+
a: number,
574+
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 224, 10))
575+
576+
b: number
577+
>b : Symbol(b, Decl(exhaustiveSwitchStatements1.ts, 225, 14))
578+
579+
};
580+
type K = keyof O | 'c';
581+
>K : Symbol(K, Decl(exhaustiveSwitchStatements1.ts, 227, 2))
582+
>O : Symbol(O, Decl(exhaustiveSwitchStatements1.ts, 220, 1))
583+
584+
function ff(o: O, k: K) {
585+
>ff : Symbol(ff, Decl(exhaustiveSwitchStatements1.ts, 228, 23))
586+
>o : Symbol(o, Decl(exhaustiveSwitchStatements1.ts, 229, 12))
587+
>O : Symbol(O, Decl(exhaustiveSwitchStatements1.ts, 220, 1))
588+
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
589+
>K : Symbol(K, Decl(exhaustiveSwitchStatements1.ts, 227, 2))
590+
591+
switch(k) {
592+
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
593+
594+
case 'c':
595+
k = 'a';
596+
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
597+
}
598+
k === 'c'; // Error
599+
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
600+
601+
return o[k];
602+
>o : Symbol(o, Decl(exhaustiveSwitchStatements1.ts, 229, 12))
603+
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
604+
}
605+

tests/baselines/reference/exhaustiveSwitchStatements1.types

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,3 +662,45 @@ function foo() {
662662
}
663663
}
664664

665+
// Repro from #35070
666+
667+
type O = {
668+
>O : O
669+
670+
a: number,
671+
>a : number
672+
673+
b: number
674+
>b : number
675+
676+
};
677+
type K = keyof O | 'c';
678+
>K : K
679+
680+
function ff(o: O, k: K) {
681+
>ff : (o: O, k: K) => number
682+
>o : O
683+
>k : K
684+
685+
switch(k) {
686+
>k : K
687+
688+
case 'c':
689+
>'c' : "c"
690+
691+
k = 'a';
692+
>k = 'a' : "a"
693+
>k : K
694+
>'a' : "a"
695+
}
696+
k === 'c'; // Error
697+
>k === 'c' : boolean
698+
>k : "a" | "b"
699+
>'c' : "c"
700+
701+
return o[k];
702+
>o[k] : number
703+
>o : O
704+
>k : "a" | "b"
705+
}
706+

tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,19 @@ function foo() {
223223
}
224224
}
225225
}
226+
227+
// Repro from #35070
228+
229+
type O = {
230+
a: number,
231+
b: number
232+
};
233+
type K = keyof O | 'c';
234+
function ff(o: O, k: K) {
235+
switch(k) {
236+
case 'c':
237+
k = 'a';
238+
}
239+
k === 'c'; // Error
240+
return o[k];
241+
}

0 commit comments

Comments
 (0)