diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6846807c3af..999934e351c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17827,8 +17827,8 @@ namespace ts { if (!(func.flags & NodeFlags.HasImplicitReturn)) { return false; } - const lastStatement = lastOrUndefined((func.body).statements); - if (lastStatement && lastStatement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(lastStatement)) { + + if (some((func.body).statements, statement => statement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(statement))) { return false; } return true; diff --git a/tests/baselines/reference/exhaustiveSwitchImplicitReturn.errors.txt b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.errors.txt new file mode 100644 index 00000000000..43b5467f0d2 --- /dev/null +++ b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.errors.txt @@ -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; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/exhaustiveSwitchImplicitReturn.js b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.js new file mode 100644 index 00000000000..5f8bf348c5f --- /dev/null +++ b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.js @@ -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; + } +} diff --git a/tests/baselines/reference/exhaustiveSwitchImplicitReturn.symbols b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.symbols new file mode 100644 index 00000000000..d93a5228362 --- /dev/null +++ b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.symbols @@ -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; + } +} + diff --git a/tests/baselines/reference/exhaustiveSwitchImplicitReturn.types b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.types new file mode 100644 index 00000000000..c868aa99b8f --- /dev/null +++ b/tests/baselines/reference/exhaustiveSwitchImplicitReturn.types @@ -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 + } +} + diff --git a/tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts b/tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts new file mode 100644 index 00000000000..b87baffdaf9 --- /dev/null +++ b/tests/cases/compiler/exhaustiveSwitchImplicitReturn.ts @@ -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; + } +}