Skip to content

do not report 'noImplicitReturns' error if inferred return type of th… #5824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9871,31 +9871,39 @@ namespace ts {
}

// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "explicitly specified"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'explicitly specified' reflects what is checked in the if below - if function has explicit type annotation and it is void / any

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the second "with"

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 or 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) {
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about func.type || func.name || func

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error already picks name as a best error span for functions if this is possible

}
}

function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, contextualMapper?: TypeMapper): Type {
Expand Down
5 changes: 1 addition & 4 deletions tests/baselines/reference/reachabilityChecks6.errors.txt
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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);
Expand All @@ -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();
}
Expand Down
32 changes: 25 additions & 7 deletions tests/baselines/reference/reachabilityChecks7.errors.txt
Original file line number Diff line number Diff line change
@@ -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"); }
37 changes: 36 additions & 1 deletion tests/baselines/reference/reachabilityChecks7.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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"); };
20 changes: 19 additions & 1 deletion tests/cases/compiler/reachabilityChecks7.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"); }