Skip to content

Commit 1728f7c

Browse files
Changed check on annotated functions/getters to only look for return statements.
1 parent 69018e6 commit 1728f7c

6 files changed

+262
-160
lines changed

src/compiler/checker.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3963,13 +3963,13 @@ module ts {
39633963
return voidType;
39643964
}
39653965

3966-
// WARNING: This has the same semantics as forEach, in that traversal terminates
3967-
// in the event that 'visitor' supplies a truthy value!
3968-
function visitReturnStatements<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
3966+
// WARNING: This has the same semantics as the forEach family of functions,
3967+
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
3968+
function forEachReturnStatement<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
39693969

3970-
return visitHelper(body);
3970+
return traverse(body);
39713971

3972-
function visitHelper(node: Node): T {
3972+
function traverse(node: Node): T {
39733973
switch (node.kind) {
39743974
case SyntaxKind.ReturnStatement:
39753975
return visitor(node);
@@ -3989,7 +3989,7 @@ module ts {
39893989
case SyntaxKind.TryBlock:
39903990
case SyntaxKind.CatchBlock:
39913991
case SyntaxKind.FinallyBlock:
3992-
return forEachChild(node, visitHelper);
3992+
return forEachChild(node, traverse);
39933993
}
39943994
}
39953995
}
@@ -3998,7 +3998,7 @@ module ts {
39983998
function checkAndAggregateReturnExpressionTypes(body: Block, contextualType?: Type, contextualMapper?: TypeMapper): Type[] {
39993999
var aggregatedTypes: Type[] = [];
40004000

4001-
visitReturnStatements(body, (returnStatement) => {
4001+
forEachReturnStatement(body, (returnStatement) => {
40024002
var expr = returnStatement.expression;
40034003
if (expr) {
40044004
var type = checkAndMarkExpression(expr, contextualType, contextualMapper);
@@ -4011,9 +4011,9 @@ module ts {
40114011
return aggregatedTypes;
40124012
}
40134013

4014-
function bodyContainsReturnExpressions(funcBody: Block) {
4015-
return visitReturnStatements(funcBody, (returnStatement) => {
4016-
return returnStatement.expression !== undefined;
4014+
function bodyContainsAReturnStatement(funcBody: Block) {
4015+
return forEachReturnStatement(funcBody, (returnStatement) => {
4016+
return true;
40174017
});
40184018
}
40194019

@@ -4039,7 +4039,7 @@ module ts {
40394039
var bodyBlock = <Block>func.body;
40404040

40414041
// Ensure the body has at least one return expression.
4042-
if (bodyContainsReturnExpressions(bodyBlock)) {
4042+
if (bodyContainsAReturnStatement(bodyBlock)) {
40434043
return;
40444044
}
40454045

@@ -4653,7 +4653,7 @@ module ts {
46534653

46544654
function checkAccessorDeclaration(node: AccessorDeclaration) {
46554655
if (node.kind === SyntaxKind.GetAccessor) {
4656-
if (!isInAmbientContext(node) && node.body && !(bodyContainsReturnExpressions(<Block>node.body) || bodyContainsSingleThrowStatement(<Block>node.body))) {
4656+
if (!isInAmbientContext(node) && node.body && !(bodyContainsAReturnStatement(<Block>node.body) || bodyContainsSingleThrowStatement(<Block>node.body))) {
46574657
error(node.name, Diagnostics.A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement);
46584658
}
46594659
}

tests/baselines/reference/functionImplementations.errors.txt

Lines changed: 0 additions & 127 deletions
This file was deleted.

tests/baselines/reference/functionReturn.errors.txt

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts (5 errors) ====
2+
3+
function f1(): string {
4+
~~~~~~
5+
!!! A function whose declared type is neither 'void' nor 'any' must have a 'return' expression or consist of a single 'throw' statement.
6+
// errors because there are no return statements
7+
}
8+
9+
function f2(): string {
10+
// Permissible; returns undefined.
11+
return;
12+
}
13+
14+
function f3(): string {
15+
return "Okay, because this is a return expression.";
16+
}
17+
18+
function f4(): void {
19+
// Fine since we are typed void.
20+
}
21+
22+
function f5(): void {
23+
// Fine since we are typed void.
24+
return;
25+
}
26+
27+
function f6(): void {
28+
// Fine since we are typed void and return undefined
29+
return undefined;
30+
}
31+
32+
function f7(): void {
33+
// Fine since we are typed void and return null
34+
return null;
35+
}
36+
37+
function f8(): void {
38+
// Fine since are typed any.
39+
return;
40+
}
41+
42+
function f9(): void {
43+
// Fine since we are typed any and return undefined
44+
return undefined;
45+
}
46+
47+
function f10(): void {
48+
// Fine since we are typed any and return null
49+
return null;
50+
}
51+
52+
function f11(): string {
53+
// Fine since we consist of a single throw statement.
54+
throw undefined;
55+
}
56+
57+
function f12(): void {
58+
// Fine since we consist of a single throw statement.
59+
throw undefined;
60+
}
61+
62+
function f13(): any {
63+
// Fine since we consist of a single throw statement.
64+
throw undefined;
65+
}
66+
67+
function f14(): number {
68+
~~~~~~
69+
!!! A function whose declared type is neither 'void' nor 'any' must have a 'return' expression or consist of a single 'throw' statement.
70+
// Not fine, since we can *only* consist of a single throw statement
71+
// if no return statements are present but we are annotated.
72+
throw undefined;
73+
throw null;
74+
}
75+
76+
function f15(): number {
77+
// Fine, since we have a return statement somewhere.
78+
throw undefined;
79+
throw null;
80+
return;
81+
}
82+
83+
84+
function f16() {
85+
// Okay; not type annotated.
86+
}
87+
88+
function f17() {
89+
// Okay; not type annotated.
90+
return;
91+
}
92+
93+
function f18() {
94+
return "Okay, not type annotated.";
95+
}
96+
97+
98+
class C {
99+
public get m1() {
100+
~~
101+
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
102+
// Errors; get accessors must return a value.
103+
}
104+
105+
public get m2() {
106+
// Permissible; returns undefined.
107+
return;
108+
}
109+
110+
public get m3() {
111+
return "Okay, because this is a return expression.";
112+
}
113+
114+
public get m4() {
115+
// Fine since this consists of a single throw statement.
116+
throw null;
117+
}
118+
119+
public get m5() {
120+
~~
121+
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
122+
// Not fine, since we can *only* consist of a single throw statement
123+
// if no return statements are present but we are a get accessor.
124+
throw null;
125+
throw undefined.
126+
}
127+
~
128+
!!! Identifier expected.
129+
}
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
==== tests/cases/conformance/parser/ecmascript5/Statements/ReturnStatements/parserReturnStatement4.ts (2 errors) ====
1+
==== tests/cases/conformance/parser/ecmascript5/Statements/ReturnStatements/parserReturnStatement4.ts (1 errors) ====
22
var v = { get foo() { return } };
33
~~~
4-
!!! Accessors are only available when targeting ECMAScript 5 and higher.
5-
~~~
6-
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
4+
!!! Accessors are only available when targeting ECMAScript 5 and higher.

0 commit comments

Comments
 (0)