Skip to content

Commit 937ce71

Browse files
committed
Merge pull request #5733 from Microsoft/unconditionalNoImplicitReturns
apply 'noImplicitReturns' rule for functions that don't have type an…
2 parents 995f0c4 + 5eb8f71 commit 937ce71

File tree

7 files changed

+644
-27
lines changed

7 files changed

+644
-27
lines changed

src/compiler/checker.ts

+27-27
Original file line numberDiff line numberDiff line change
@@ -9854,17 +9854,25 @@ namespace ts {
98549854
return aggregatedTypes;
98559855
}
98569856

9857-
// TypeScript Specification 1.0 (6.3) - July 2014
9858-
// An explicitly typed function whose return type isn't the Void or the Any type
9859-
// must have at least one return statement somewhere in its body.
9860-
// An exception to this rule is if the function implementation consists of a single 'throw' statement.
9857+
/*
9858+
*TypeScript Specification 1.0 (6.3) - July 2014
9859+
* An explicitly typed function whose return type isn't the Void or the Any type
9860+
* must have at least one return statement somewhere in its body.
9861+
* An exception to this rule is if the function implementation consists of a single 'throw' statement.
9862+
* @param returnType - return type of the function, can be undefined if return type is not explicitly specified
9863+
*/
98619864
function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration, returnType: Type): void {
98629865
if (!produceDiagnostics) {
98639866
return;
98649867
}
98659868

9866-
// Functions that return 'void' or 'any' don't need any return expressions.
9867-
if (returnType === voidType || isTypeAny(returnType)) {
9869+
// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
9870+
if (returnType && (returnType === voidType || isTypeAny(returnType))) {
9871+
return;
9872+
}
9873+
9874+
// if return type is not specified then we'll do the check only if 'noImplicitReturns' option is set
9875+
if (!returnType && !compilerOptions.noImplicitReturns) {
98689876
return;
98699877
}
98709878

@@ -9874,13 +9882,14 @@ namespace ts {
98749882
return;
98759883
}
98769884

9877-
if (func.flags & NodeFlags.HasExplicitReturn) {
9885+
if (!returnType || func.flags & NodeFlags.HasExplicitReturn) {
98789886
if (compilerOptions.noImplicitReturns) {
9879-
error(func.type, Diagnostics.Not_all_code_paths_return_a_value);
9887+
error(func.type || func, Diagnostics.Not_all_code_paths_return_a_value);
98809888
}
98819889
}
98829890
else {
98839891
// This function does not conform to the specification.
9892+
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
98849893
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
98859894
}
98869895
}
@@ -9955,14 +9964,10 @@ namespace ts {
99559964
emitAwaiter = true;
99569965
}
99579966

9958-
const returnType = node.type && getTypeFromTypeNode(node.type);
9959-
let promisedType: Type;
9960-
if (returnType && isAsync) {
9961-
promisedType = checkAsyncFunctionReturnType(node);
9962-
}
9963-
9964-
if (returnType && !node.asteriskToken) {
9965-
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, isAsync ? promisedType : returnType);
9967+
const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type));
9968+
if (!node.asteriskToken) {
9969+
// return is not necessary in the body of generators
9970+
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType);
99669971
}
99679972

99689973
if (node.body) {
@@ -9985,13 +9990,13 @@ namespace ts {
99859990
// check assignability of the awaited type of the expression body against the promised type of
99869991
// its return type annotation.
99879992
const exprType = checkExpression(<Expression>node.body);
9988-
if (returnType) {
9993+
if (returnOrPromisedType) {
99899994
if (isAsync) {
99909995
const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member);
9991-
checkTypeAssignableTo(awaitedType, promisedType, node.body);
9996+
checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body);
99929997
}
99939998
else {
9994-
checkTypeAssignableTo(exprType, returnType, node.body);
9999+
checkTypeAssignableTo(exprType, returnOrPromisedType, node.body);
999510000
}
999610001
}
999710002

@@ -12131,14 +12136,9 @@ namespace ts {
1213112136
}
1213212137

1213312138
checkSourceElement(node.body);
12134-
if (node.type && !isAccessor(node.kind) && !node.asteriskToken) {
12135-
const returnType = getTypeFromTypeNode(node.type);
12136-
let promisedType: Type;
12137-
if (isAsync) {
12138-
promisedType = checkAsyncFunctionReturnType(node);
12139-
}
12140-
12141-
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, isAsync ? promisedType : returnType);
12139+
if (!isAccessor(node.kind) && !node.asteriskToken) {
12140+
const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type));
12141+
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType);
1214212142
}
1214312143

1214412144
if (produceDiagnostics && !node.type) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
tests/cases/compiler/reachabilityChecks6.ts(6,10): error TS7030: Not all code paths return a value.
2+
tests/cases/compiler/reachabilityChecks6.ts(19,10): error TS7030: Not all code paths return a value.
3+
tests/cases/compiler/reachabilityChecks6.ts(31,10): error TS7030: Not all code paths return a value.
4+
tests/cases/compiler/reachabilityChecks6.ts(41,10): error TS7030: Not all code paths return a value.
5+
tests/cases/compiler/reachabilityChecks6.ts(52,10): error TS7030: Not all code paths return a value.
6+
tests/cases/compiler/reachabilityChecks6.ts(80,10): error TS7030: Not all code paths return a value.
7+
tests/cases/compiler/reachabilityChecks6.ts(86,13): error TS7027: Unreachable code detected.
8+
tests/cases/compiler/reachabilityChecks6.ts(94,10): error TS7030: Not all code paths return a value.
9+
tests/cases/compiler/reachabilityChecks6.ts(116,10): error TS7030: Not all code paths return a value.
10+
tests/cases/compiler/reachabilityChecks6.ts(123,13): error TS7027: Unreachable code detected.
11+
12+
13+
==== tests/cases/compiler/reachabilityChecks6.ts (10 errors) ====
14+
15+
function f0(x) {
16+
while (true);
17+
}
18+
19+
function f1(x) {
20+
~~
21+
!!! error TS7030: Not all code paths return a value.
22+
if (x) {
23+
return 1
24+
}
25+
}
26+
27+
function f2(x) {
28+
while (x) {
29+
throw new Error();
30+
}
31+
return 1;
32+
}
33+
34+
function f3(x) {
35+
~~
36+
!!! error TS7030: Not all code paths return a value.
37+
while (x) {
38+
throw new Error();
39+
}
40+
}
41+
42+
function f3_1 (x) {
43+
while (x) {
44+
}
45+
throw new Error();
46+
}
47+
48+
function f4(x) {
49+
~~
50+
!!! error TS7030: Not all code paths return a value.
51+
try {
52+
if (x) {
53+
return 1;
54+
}
55+
}
56+
catch (e) {
57+
}
58+
}
59+
60+
function f5(x) {
61+
~~
62+
!!! error TS7030: Not all code paths return a value.
63+
try {
64+
if (x) {
65+
return 1;
66+
}
67+
}
68+
catch (e) {
69+
return 2;
70+
}
71+
}
72+
73+
function f6(x) {
74+
~~
75+
!!! error TS7030: Not all code paths return a value.
76+
try {
77+
if (x) {
78+
return 1;
79+
}
80+
else
81+
{
82+
throw new Error();
83+
}
84+
}
85+
catch (e) {
86+
}
87+
}
88+
89+
function f7(x) {
90+
try {
91+
if (x) {
92+
return 1;
93+
}
94+
else {
95+
throw new Error();
96+
}
97+
}
98+
catch (e) {
99+
return 1;
100+
}
101+
}
102+
103+
function f8(x) {
104+
~~
105+
!!! error TS7030: Not all code paths return a value.
106+
try {
107+
if (true) {
108+
x++;
109+
}
110+
else {
111+
return 1;
112+
~~~~~~
113+
!!! error TS7027: Unreachable code detected.
114+
}
115+
}
116+
catch (e) {
117+
return 1;
118+
}
119+
}
120+
121+
function f9(x) {
122+
~~
123+
!!! error TS7030: Not all code paths return a value.
124+
try {
125+
while (false) {
126+
return 1;
127+
}
128+
}
129+
catch (e) {
130+
return 1;
131+
}
132+
}
133+
134+
function f10(x) {
135+
try {
136+
do {
137+
x++;
138+
} while (true);
139+
}
140+
catch (e) {
141+
return 1;
142+
}
143+
}
144+
145+
function f11(x) {
146+
~~~
147+
!!! error TS7030: Not all code paths return a value.
148+
test:
149+
try {
150+
do {
151+
do {
152+
break test;
153+
} while (true);
154+
x++;
155+
~
156+
!!! error TS7027: Unreachable code detected.
157+
} while (true);
158+
}
159+
catch (e) {
160+
return 1;
161+
}
162+
}

0 commit comments

Comments
 (0)