do not report 'noImplicitReturns' error if inferred return type of the function is void/any

This commit is contained in:
Vladimir Matveev 2015-11-28 23:20:53 -08:00
parent 2f282a786a
commit d0e4a4ca92
5 changed files with 104 additions and 27 deletions

View file

@ -9871,31 +9871,40 @@ namespace ts {
}
// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
if (returnType && (returnType === voidType || isTypeAny(returnType))) {
return;
}
// if return type is not specified then we'll do the check only if 'noImplicitReturns' option is set
if (!returnType && !compilerOptions.noImplicitReturns) {
if (returnType === voidType || isTypeAny(returnType)) {
return;
}
// If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check.
// also if HasImplicitReturnValue flags is not set this means that all codepaths in function body end with return of throw
// also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return of throw
if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block || !(func.flags & NodeFlags.HasImplicitReturn)) {
return;
}
if (!returnType || func.flags & NodeFlags.HasExplicitReturn) {
if (compilerOptions.noImplicitReturns) {
error(func.type || func, Diagnostics.Not_all_code_paths_return_a_value);
}
}
else {
// This function does not conform to the specification.
const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn;
if (returnType && !hasExplicitReturn) {
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
// this function does not conform to the specification.
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
}
else if (compilerOptions.noImplicitReturns){
// errors in this branch should only be reported if CompilerOptions.noImplicitReturns flag is set
if (!returnType) {
// If return type annotation is omitted check if function has any explicit return statements.
// If it does not have any - its inferred return type is void - don't do any checks.
// Otherwise get inferred return type from function body and report error only if it is not void / anytype
const inferredReturnType = hasExplicitReturn
? getReturnTypeOfSignature(getSignatureFromDeclaration(func))
: voidType;
if (inferredReturnType === voidType || isTypeAny(inferredReturnType)) {
return;
}
}
error(func.type || func, Diagnostics.Not_all_code_paths_return_a_value);
}
}
function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, contextualMapper?: TypeMapper): Type {

View file

@ -1,5 +1,4 @@
tests/cases/compiler/reachabilityChecks6.ts(6,10): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks6.ts(19,10): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks6.ts(31,10): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks6.ts(41,10): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks6.ts(52,10): error TS7030: Not all code paths return a value.
@ -10,7 +9,7 @@ tests/cases/compiler/reachabilityChecks6.ts(116,10): error TS7030: Not all code
tests/cases/compiler/reachabilityChecks6.ts(123,13): error TS7027: Unreachable code detected.
==== tests/cases/compiler/reachabilityChecks6.ts (10 errors) ====
==== tests/cases/compiler/reachabilityChecks6.ts (9 errors) ====
function f0(x) {
while (true);
@ -32,8 +31,6 @@ tests/cases/compiler/reachabilityChecks6.ts(123,13): error TS7027: Unreachable c
}
function f3(x) {
~~
!!! error TS7030: Not all code paths return a value.
while (x) {
throw new Error();
}

View file

@ -1,21 +1,39 @@
tests/cases/compiler/reachabilityChecks7.ts(3,16): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks7.ts(6,9): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks7.ts(14,16): error TS7030: Not all code paths return a value.
tests/cases/compiler/reachabilityChecks7.ts(18,22): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
==== tests/cases/compiler/reachabilityChecks7.ts (2 errors) ====
// async function without return type annotation - error
async function f1() {
~~
!!! error TS7030: Not all code paths return a value.
}
let x = async function() {
~~~~~
!!! error TS7030: Not all code paths return a value.
}
// async function with which promised type is void - return can be omitted
async function f2(): Promise<void> {
}
}
async function f3(x) {
~~
!!! error TS7030: Not all code paths return a value.
if (x) return 10;
}
async function f4(): Promise<number> {
~~~~~~~~~~~~~~~
!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
}
function voidFunc(): void {
}
function calltoVoidFunc(x) {
if (x) return voidFunc();
}
declare function use(s: string): void;
let x1 = () => { use("Test"); }

View file

@ -10,7 +10,25 @@ let x = async function() {
// async function with which promised type is void - return can be omitted
async function f2(): Promise<void> {
}
}
async function f3(x) {
if (x) return 10;
}
async function f4(): Promise<number> {
}
function voidFunc(): void {
}
function calltoVoidFunc(x) {
if (x) return voidFunc();
}
declare function use(s: string): void;
let x1 = () => { use("Test"); }
//// [reachabilityChecks7.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
@ -40,3 +58,20 @@ function f2() {
return __awaiter(this, void 0, Promise, function* () {
});
}
function f3(x) {
return __awaiter(this, void 0, Promise, function* () {
if (x)
return 10;
});
}
function f4() {
return __awaiter(this, void 0, Promise, function* () {
});
}
function voidFunc() {
}
function calltoVoidFunc(x) {
if (x)
return voidFunc();
}
let x1 = () => { use("Test"); };

View file

@ -11,4 +11,22 @@ let x = async function() {
// async function with which promised type is void - return can be omitted
async function f2(): Promise<void> {
}
}
async function f3(x) {
if (x) return 10;
}
async function f4(): Promise<number> {
}
function voidFunc(): void {
}
function calltoVoidFunc(x) {
if (x) return voidFunc();
}
declare function use(s: string): void;
let x1 = () => { use("Test"); }