Treat exhaustive switch as last statement in function #18882 (#20063)

This commit is contained in:
Charles Pierce 2017-11-16 12:17:26 -08:00 committed by Mohamed Hegazy
parent 478b404f42
commit 1da35d9dca
6 changed files with 326 additions and 2 deletions

View File

@ -17827,8 +17827,8 @@ namespace ts {
if (!(func.flags & NodeFlags.HasImplicitReturn)) {
return false;
}
const lastStatement = lastOrUndefined((<Block>func.body).statements);
if (lastStatement && lastStatement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(<SwitchStatement>lastStatement)) {
if (some((<Block>func.body).statements, statement => statement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(<SwitchStatement>statement))) {
return false;
}
return true;

View File

@ -0,0 +1,47 @@
tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts(35,32): error TS7030: Not all code paths return a value.
==== tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts (1 errors) ====
function foo1(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
}
function foo2(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
let unusedVariable;
}
function foo3(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
function neverCalled() {}
}
function foo4(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
foo3(bar);
}
function foo5(bar: "a" | "b"): number {
~~~~~~
!!! error TS7030: Not all code paths return a value.
switch(bar) {
case "a":
return 1;
}
}

View File

@ -0,0 +1,77 @@
//// [exhaustiveSwitchImplicitReturn.ts]
function foo1(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
}
function foo2(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
let unusedVariable;
}
function foo3(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
function neverCalled() {}
}
function foo4(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
foo3(bar);
}
function foo5(bar: "a" | "b"): number {
switch(bar) {
case "a":
return 1;
}
}
//// [exhaustiveSwitchImplicitReturn.js]
function foo1(bar) {
switch (bar) {
case "a":
return 1;
}
}
function foo2(bar) {
switch (bar) {
case "a":
return 1;
}
var unusedVariable;
}
function foo3(bar) {
switch (bar) {
case "a":
return 1;
}
function neverCalled() { }
}
function foo4(bar) {
switch (bar) {
case "a":
return 1;
}
foo3(bar);
}
function foo5(bar) {
switch (bar) {
case "a":
return 1;
}
}

View File

@ -0,0 +1,71 @@
=== tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts ===
function foo1(bar: "a"): number {
>foo1 : Symbol(foo1, Decl(exhaustiveSwitchImplicitReturn.ts, 0, 0))
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 0, 14))
switch(bar) {
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 0, 14))
case "a":
return 1;
}
}
function foo2(bar: "a"): number {
>foo2 : Symbol(foo2, Decl(exhaustiveSwitchImplicitReturn.ts, 5, 1))
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 7, 14))
switch(bar) {
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 7, 14))
case "a":
return 1;
}
let unusedVariable;
>unusedVariable : Symbol(unusedVariable, Decl(exhaustiveSwitchImplicitReturn.ts, 13, 7))
}
function foo3(bar: "a"): number {
>foo3 : Symbol(foo3, Decl(exhaustiveSwitchImplicitReturn.ts, 14, 1))
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 16, 14))
switch(bar) {
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 16, 14))
case "a":
return 1;
}
function neverCalled() {}
>neverCalled : Symbol(neverCalled, Decl(exhaustiveSwitchImplicitReturn.ts, 20, 5))
}
function foo4(bar: "a"): number {
>foo4 : Symbol(foo4, Decl(exhaustiveSwitchImplicitReturn.ts, 23, 1))
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 25, 14))
switch(bar) {
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 25, 14))
case "a":
return 1;
}
foo3(bar);
>foo3 : Symbol(foo3, Decl(exhaustiveSwitchImplicitReturn.ts, 14, 1))
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 25, 14))
}
function foo5(bar: "a" | "b"): number {
>foo5 : Symbol(foo5, Decl(exhaustiveSwitchImplicitReturn.ts, 32, 1))
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 34, 14))
switch(bar) {
>bar : Symbol(bar, Decl(exhaustiveSwitchImplicitReturn.ts, 34, 14))
case "a":
return 1;
}
}

View File

@ -0,0 +1,87 @@
=== tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts ===
function foo1(bar: "a"): number {
>foo1 : (bar: "a") => number
>bar : "a"
switch(bar) {
>bar : "a"
case "a":
>"a" : "a"
return 1;
>1 : 1
}
}
function foo2(bar: "a"): number {
>foo2 : (bar: "a") => number
>bar : "a"
switch(bar) {
>bar : "a"
case "a":
>"a" : "a"
return 1;
>1 : 1
}
let unusedVariable;
>unusedVariable : any
}
function foo3(bar: "a"): number {
>foo3 : (bar: "a") => number
>bar : "a"
switch(bar) {
>bar : "a"
case "a":
>"a" : "a"
return 1;
>1 : 1
}
function neverCalled() {}
>neverCalled : () => void
}
function foo4(bar: "a"): number {
>foo4 : (bar: "a") => number
>bar : "a"
switch(bar) {
>bar : "a"
case "a":
>"a" : "a"
return 1;
>1 : 1
}
foo3(bar);
>foo3(bar) : number
>foo3 : (bar: "a") => number
>bar : never
}
function foo5(bar: "a" | "b"): number {
>foo5 : (bar: "a" | "b") => number
>bar : "a" | "b"
switch(bar) {
>bar : "a" | "b"
case "a":
>"a" : "a"
return 1;
>1 : 1
}
}

View File

@ -0,0 +1,42 @@
// @noImplicitReturns: true
function foo1(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
}
function foo2(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
let unusedVariable;
}
function foo3(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
function neverCalled() {}
}
function foo4(bar: "a"): number {
switch(bar) {
case "a":
return 1;
}
foo3(bar);
}
function foo5(bar: "a" | "b"): number {
switch(bar) {
case "a":
return 1;
}
}