Properly analyze switch statement bypass control flow (#35087)

* Properly analyze switch statement bypass control flow

* Add regression test

* Accept new baselines
This commit is contained in:
Anders Hejlsberg 2019-11-13 09:22:18 -08:00 committed by GitHub
parent aa39080ac7
commit 38db7ae59e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 147 additions and 2 deletions

View file

@ -19333,7 +19333,7 @@ namespace ts {
}
}
if (bypassFlow) {
const flowType = getTypeAtFlowNode(bypassFlow.antecedent);
const flowType = getTypeAtFlowNode(bypassFlow);
const type = getTypeFromFlowType(flowType);
// If the bypass flow contributes a type we haven't seen yet and the switch statement
// isn't exhaustive, process the bypass flow type. Since exhaustiveness checks increase

View file

@ -1,7 +1,8 @@
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error TS7027: Unreachable code detected.
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.
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (1 errors) ====
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (2 errors) ====
function f1(x: 1 | 2): string {
if (!!true) {
switch (x) {
@ -225,4 +226,22 @@ tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error T
}
}
}
// Repro from #35070
type O = {
a: number,
b: number
};
type K = keyof O | 'c';
function ff(o: O, k: K) {
switch(k) {
case 'c':
k = 'a';
}
k === 'c'; // Error
~~~~~~~~~
!!! error TS2367: This condition will always return 'false' since the types '"a" | "b"' and '"c"' have no overlap.
return o[k];
}

View file

@ -220,6 +220,22 @@ function foo() {
}
}
}
// Repro from #35070
type O = {
a: number,
b: number
};
type K = keyof O | 'c';
function ff(o: O, k: K) {
switch(k) {
case 'c':
k = 'a';
}
k === 'c'; // Error
return o[k];
}
//// [exhaustiveSwitchStatements1.js]
@ -429,6 +445,14 @@ function foo() {
}
}
}
function ff(o, k) {
switch (k) {
case 'c':
k = 'a';
}
k === 'c'; // Error
return o[k];
}
//// [exhaustiveSwitchStatements1.d.ts]
@ -494,3 +518,9 @@ declare const zoo: {
} | undefined;
declare function expression(): Animal;
declare function foo(): void;
declare type O = {
a: number;
b: number;
};
declare type K = keyof O | 'c';
declare function ff(o: O, k: K): number;

View file

@ -565,3 +565,41 @@ function foo() {
}
}
// Repro from #35070
type O = {
>O : Symbol(O, Decl(exhaustiveSwitchStatements1.ts, 220, 1))
a: number,
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 224, 10))
b: number
>b : Symbol(b, Decl(exhaustiveSwitchStatements1.ts, 225, 14))
};
type K = keyof O | 'c';
>K : Symbol(K, Decl(exhaustiveSwitchStatements1.ts, 227, 2))
>O : Symbol(O, Decl(exhaustiveSwitchStatements1.ts, 220, 1))
function ff(o: O, k: K) {
>ff : Symbol(ff, Decl(exhaustiveSwitchStatements1.ts, 228, 23))
>o : Symbol(o, Decl(exhaustiveSwitchStatements1.ts, 229, 12))
>O : Symbol(O, Decl(exhaustiveSwitchStatements1.ts, 220, 1))
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
>K : Symbol(K, Decl(exhaustiveSwitchStatements1.ts, 227, 2))
switch(k) {
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
case 'c':
k = 'a';
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
}
k === 'c'; // Error
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
return o[k];
>o : Symbol(o, Decl(exhaustiveSwitchStatements1.ts, 229, 12))
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
}

View file

@ -662,3 +662,45 @@ function foo() {
}
}
// Repro from #35070
type O = {
>O : O
a: number,
>a : number
b: number
>b : number
};
type K = keyof O | 'c';
>K : K
function ff(o: O, k: K) {
>ff : (o: O, k: K) => number
>o : O
>k : K
switch(k) {
>k : K
case 'c':
>'c' : "c"
k = 'a';
>k = 'a' : "a"
>k : K
>'a' : "a"
}
k === 'c'; // Error
>k === 'c' : boolean
>k : "a" | "b"
>'c' : "c"
return o[k];
>o[k] : number
>o : O
>k : "a" | "b"
}

View file

@ -223,3 +223,19 @@ function foo() {
}
}
}
// Repro from #35070
type O = {
a: number,
b: number
};
type K = keyof O | 'c';
function ff(o: O, k: K) {
switch(k) {
case 'c':
k = 'a';
}
k === 'c'; // Error
return o[k];
}