mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Fixed narrowing in case clauses that follow other clauses that return (#56358)
This commit is contained in:
parent
70becf9af9
commit
9f15002959
@ -1689,9 +1689,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
|
||||
const clauses = node.clauses;
|
||||
const isNarrowingSwitch = node.parent.expression.kind === SyntaxKind.TrueKeyword || isNarrowingExpression(node.parent.expression);
|
||||
let fallthroughFlow = unreachableFlow;
|
||||
|
||||
for (let i = 0; i < clauses.length; i++) {
|
||||
const clauseStart = i;
|
||||
while (!clauses[i].statements.length && i + 1 < clauses.length) {
|
||||
if (fallthroughFlow === unreachableFlow) {
|
||||
currentFlow = preSwitchCaseFlow!;
|
||||
}
|
||||
bind(clauses[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -0,0 +1,126 @@
|
||||
//// [tests/cases/compiler/narrowingInCaseClauseAfterCaseClauseWithReturn.ts] ////
|
||||
|
||||
=== narrowingInCaseClauseAfterCaseClauseWithReturn.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/56352
|
||||
|
||||
function test1(arg: string | undefined) {
|
||||
>test1 : Symbol(test1, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 0, 0))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 2, 15))
|
||||
|
||||
if (!arg) throw new Error();
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 2, 15))
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
switch (true) {
|
||||
case arg.toUpperCase() === "A":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 2, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
return "A";
|
||||
|
||||
case arg.toUpperCase() === "B":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 2, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
case arg.toUpperCase() === "C":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 2, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
case arg.toUpperCase() === "D":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 2, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
return "B, C or D";
|
||||
}
|
||||
|
||||
return "Not A, B, C or D";
|
||||
}
|
||||
|
||||
function test2(arg: string | undefined) {
|
||||
>test2 : Symbol(test2, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 16, 1))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 18, 15))
|
||||
|
||||
if (!arg) throw new Error();
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 18, 15))
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
switch (true) {
|
||||
case arg.toUpperCase() === "A":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 18, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
case arg.toUpperCase() === "B":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 18, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
case arg.toUpperCase() === "C":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 18, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
return "A, B or C";
|
||||
case arg.toUpperCase() === "D":
|
||||
>arg.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>arg : Symbol(arg, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 18, 15))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
return "D";
|
||||
}
|
||||
|
||||
return "Not A, B, C or D";
|
||||
}
|
||||
|
||||
function test3(
|
||||
>test3 : Symbol(test3, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 31, 1))
|
||||
|
||||
foo:
|
||||
>foo : Symbol(foo, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 33, 15))
|
||||
|
||||
| { kind: "a"; prop: string }
|
||||
>kind : Symbol(kind, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 35, 7))
|
||||
>prop : Symbol(prop, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 35, 18))
|
||||
|
||||
| { kind: "b"; prop: number }
|
||||
>kind : Symbol(kind, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 36, 7))
|
||||
>prop : Symbol(prop, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 36, 18))
|
||||
|
||||
| { kind: "c"; prop: boolean },
|
||||
>kind : Symbol(kind, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 7))
|
||||
>prop : Symbol(prop, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 18))
|
||||
|
||||
bar?: {
|
||||
>bar : Symbol(bar, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 35))
|
||||
|
||||
type: "b";
|
||||
>type : Symbol(type, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 38, 9))
|
||||
|
||||
},
|
||||
) {
|
||||
if (!bar) {
|
||||
>bar : Symbol(bar, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 35))
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (foo.kind) {
|
||||
>foo.kind : Symbol(kind, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 35, 7), Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 36, 7), Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 7))
|
||||
>foo : Symbol(foo, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 33, 15))
|
||||
>kind : Symbol(kind, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 35, 7), Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 36, 7), Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 7))
|
||||
|
||||
case "a":
|
||||
return;
|
||||
case bar.type:
|
||||
>bar.type : Symbol(type, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 38, 9))
|
||||
>bar : Symbol(bar, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 37, 35))
|
||||
>type : Symbol(type, Decl(narrowingInCaseClauseAfterCaseClauseWithReturn.ts, 38, 9))
|
||||
|
||||
case "c":
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
//// [tests/cases/compiler/narrowingInCaseClauseAfterCaseClauseWithReturn.ts] ////
|
||||
|
||||
=== narrowingInCaseClauseAfterCaseClauseWithReturn.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/56352
|
||||
|
||||
function test1(arg: string | undefined) {
|
||||
>test1 : (arg: string | undefined) => "A" | "B, C or D" | "Not A, B, C or D"
|
||||
>arg : string | undefined
|
||||
|
||||
if (!arg) throw new Error();
|
||||
>!arg : boolean
|
||||
>arg : string | undefined
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
|
||||
switch (true) {
|
||||
>true : true
|
||||
|
||||
case arg.toUpperCase() === "A":
|
||||
>arg.toUpperCase() === "A" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"A" : "A"
|
||||
|
||||
return "A";
|
||||
>"A" : "A"
|
||||
|
||||
case arg.toUpperCase() === "B":
|
||||
>arg.toUpperCase() === "B" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"B" : "B"
|
||||
|
||||
case arg.toUpperCase() === "C":
|
||||
>arg.toUpperCase() === "C" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"C" : "C"
|
||||
|
||||
case arg.toUpperCase() === "D":
|
||||
>arg.toUpperCase() === "D" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"D" : "D"
|
||||
|
||||
return "B, C or D";
|
||||
>"B, C or D" : "B, C or D"
|
||||
}
|
||||
|
||||
return "Not A, B, C or D";
|
||||
>"Not A, B, C or D" : "Not A, B, C or D"
|
||||
}
|
||||
|
||||
function test2(arg: string | undefined) {
|
||||
>test2 : (arg: string | undefined) => "Not A, B, C or D" | "D" | "A, B or C"
|
||||
>arg : string | undefined
|
||||
|
||||
if (!arg) throw new Error();
|
||||
>!arg : boolean
|
||||
>arg : string | undefined
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
|
||||
switch (true) {
|
||||
>true : true
|
||||
|
||||
case arg.toUpperCase() === "A":
|
||||
>arg.toUpperCase() === "A" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"A" : "A"
|
||||
|
||||
case arg.toUpperCase() === "B":
|
||||
>arg.toUpperCase() === "B" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"B" : "B"
|
||||
|
||||
case arg.toUpperCase() === "C":
|
||||
>arg.toUpperCase() === "C" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"C" : "C"
|
||||
|
||||
return "A, B or C";
|
||||
>"A, B or C" : "A, B or C"
|
||||
|
||||
case arg.toUpperCase() === "D":
|
||||
>arg.toUpperCase() === "D" : boolean
|
||||
>arg.toUpperCase() : string
|
||||
>arg.toUpperCase : () => string
|
||||
>arg : string
|
||||
>toUpperCase : () => string
|
||||
>"D" : "D"
|
||||
|
||||
return "D";
|
||||
>"D" : "D"
|
||||
}
|
||||
|
||||
return "Not A, B, C or D";
|
||||
>"Not A, B, C or D" : "Not A, B, C or D"
|
||||
}
|
||||
|
||||
function test3(
|
||||
>test3 : (foo: { kind: "a"; prop: string;} | { kind: "b"; prop: number;} | { kind: "c"; prop: boolean;}, bar?: { type: "b";}) => void
|
||||
|
||||
foo:
|
||||
>foo : { kind: "a"; prop: string; } | { kind: "b"; prop: number; } | { kind: "c"; prop: boolean; }
|
||||
|
||||
| { kind: "a"; prop: string }
|
||||
>kind : "a"
|
||||
>prop : string
|
||||
|
||||
| { kind: "b"; prop: number }
|
||||
>kind : "b"
|
||||
>prop : number
|
||||
|
||||
| { kind: "c"; prop: boolean },
|
||||
>kind : "c"
|
||||
>prop : boolean
|
||||
|
||||
bar?: {
|
||||
>bar : { type: "b"; } | undefined
|
||||
|
||||
type: "b";
|
||||
>type : "b"
|
||||
|
||||
},
|
||||
) {
|
||||
if (!bar) {
|
||||
>!bar : boolean
|
||||
>bar : { type: "b"; } | undefined
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (foo.kind) {
|
||||
>foo.kind : "a" | "b" | "c"
|
||||
>foo : { kind: "a"; prop: string; } | { kind: "b"; prop: number; } | { kind: "c"; prop: boolean; }
|
||||
>kind : "a" | "b" | "c"
|
||||
|
||||
case "a":
|
||||
>"a" : "a"
|
||||
|
||||
return;
|
||||
case bar.type:
|
||||
>bar.type : "b"
|
||||
>bar : { type: "b"; }
|
||||
>type : "b"
|
||||
|
||||
case "c":
|
||||
>"c" : "c"
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/56352
|
||||
|
||||
function test1(arg: string | undefined) {
|
||||
if (!arg) throw new Error();
|
||||
|
||||
switch (true) {
|
||||
case arg.toUpperCase() === "A":
|
||||
return "A";
|
||||
|
||||
case arg.toUpperCase() === "B":
|
||||
case arg.toUpperCase() === "C":
|
||||
case arg.toUpperCase() === "D":
|
||||
return "B, C or D";
|
||||
}
|
||||
|
||||
return "Not A, B, C or D";
|
||||
}
|
||||
|
||||
function test2(arg: string | undefined) {
|
||||
if (!arg) throw new Error();
|
||||
|
||||
switch (true) {
|
||||
case arg.toUpperCase() === "A":
|
||||
case arg.toUpperCase() === "B":
|
||||
case arg.toUpperCase() === "C":
|
||||
return "A, B or C";
|
||||
case arg.toUpperCase() === "D":
|
||||
return "D";
|
||||
}
|
||||
|
||||
return "Not A, B, C or D";
|
||||
}
|
||||
|
||||
function test3(
|
||||
foo:
|
||||
| { kind: "a"; prop: string }
|
||||
| { kind: "b"; prop: number }
|
||||
| { kind: "c"; prop: boolean },
|
||||
bar?: {
|
||||
type: "b";
|
||||
},
|
||||
) {
|
||||
if (!bar) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (foo.kind) {
|
||||
case "a":
|
||||
return;
|
||||
case bar.type:
|
||||
case "c":
|
||||
return;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user