Merge pull request #147 from Microsoft/noReturnExpression

Complain when a non-void function lacks a return expresson.
This commit is contained in:
Daniel Rosenwasser 2014-07-22 13:46:54 -07:00
commit c8fc26a20a
44 changed files with 478 additions and 93 deletions

View file

@ -3972,12 +3972,10 @@ module ts {
}
// Aggregate the types of expressions within all the return statements.
var types: Type[] = [];
checkAndAggregateReturnExpressionTypes(func.body);
var types = checkAndAggregateReturnExpressionTypes(<Block>func.body, contextualType, contextualMapper);
// Try to return the best common type if we have any return expressions.
if (types.length) {
if (types.length > 0) {
var commonType = getBestCommonType(types, /*contextualType:*/ undefined, /*candidatesOnly:*/ true);
if (!commonType) {
error(func, Diagnostics.No_best_common_type_exists_among_return_expressions);
@ -4003,16 +4001,18 @@ module ts {
}
return voidType;
}
function checkAndAggregateReturnExpressionTypes(node: Node) {
// WARNING: This has the same semantics as the forEach family of functions,
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
function forEachReturnStatement<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
return traverse(body);
function traverse(node: Node): T {
switch (node.kind) {
case SyntaxKind.ReturnStatement:
var expr = (<ReturnStatement>node).expression;
if (expr) {
var type = checkAndMarkExpression(expr, contextualType, contextualMapper);
if (!contains(types, type)) types.push(type);
}
break;
return visitor(node);
case SyntaxKind.Block:
case SyntaxKind.FunctionBlock:
case SyntaxKind.IfStatement:
@ -4029,15 +4029,77 @@ module ts {
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
forEachChild(node, checkAndAggregateReturnExpressionTypes);
break;
return forEachChild(node, traverse);
}
}
}
/// Returns a set of types relating to every return expression relating to a function block.
function checkAndAggregateReturnExpressionTypes(body: Block, contextualType?: Type, contextualMapper?: TypeMapper): Type[] {
var aggregatedTypes: Type[] = [];
forEachReturnStatement(body, (returnStatement) => {
var expr = returnStatement.expression;
if (expr) {
var type = checkAndMarkExpression(expr, contextualType, contextualMapper);
if (!contains(aggregatedTypes, type)) {
aggregatedTypes.push(type);
}
}
});
return aggregatedTypes;
}
function bodyContainsAReturnStatement(funcBody: Block) {
return forEachReturnStatement(funcBody, (returnStatement) => {
return true;
});
}
function bodyContainsSingleThrowStatement(body: Block) {
return (body.statements.length === 1) && (body.statements[0].kind === SyntaxKind.ThrowStatement)
}
// TypeScript Specification 1.0 (6.3) - July 2014
// An explicitly typed function whose return type isn't the Void or the Any type
// must have at least one return statement somewhere in its body.
// An exception to this rule is if the function implementation consists of a single 'throw' statement.
function checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(func: FunctionDeclaration, returnType: Type): void {
// Functions that return 'void' or 'any' don't need any return expressions.
if (returnType === voidType || returnType === anyType) {
return;
}
// If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check.
if (!func.body || func.body.kind !== SyntaxKind.FunctionBlock) {
return;
}
var bodyBlock = <Block>func.body;
// Ensure the body has at least one return expression.
if (bodyContainsAReturnStatement(bodyBlock)) {
return;
}
// If there are no return expressions, then we need to check if
// the function body consists solely of a throw statement;
// this is to make an exception for unimplemented functions.
if (bodyContainsSingleThrowStatement(bodyBlock)) {
return;
}
// This function does not conform to the specification.
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement);
}
function checkFunctionExpression(node: FunctionExpression, contextualType?: Type, contextualMapper?: TypeMapper): Type {
// The identityMapper object is used to indicate that function expressions are wildcards
if (contextualMapper === identityMapper) return anyFunctionType;
if (contextualMapper === identityMapper) {
return anyFunctionType;
}
var type = getTypeOfSymbol(node.symbol);
var links = getNodeLinks(node);
@ -4055,6 +4117,9 @@ module ts {
signature.resolvedReturnType = returnType;
}
}
else {
checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type));
}
}
checkSignatureDeclaration(node);
if (node.body.kind === SyntaxKind.FunctionBlock) {
@ -4627,28 +4692,9 @@ module ts {
}
function checkAccessorDeclaration(node: AccessorDeclaration) {
function checkGetterContainsSingleThrowStatement(node: AccessorDeclaration): boolean {
var block = <Block>node.body;
return block.statements.length === 1 && block.statements[0].kind === SyntaxKind.ThrowStatement;
}
function checkGetterReturnsValue(n: Node): boolean {
switch (n.kind) {
case SyntaxKind.ReturnStatement:
return true;
// do not dive into function-like things - return statements there don't count
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
case SyntaxKind.ObjectLiteral:
return false;
default:
return forEachChild(n, checkGetterReturnsValue);
}
}
if (node.kind === SyntaxKind.GetAccessor) {
if (!isInAmbientContext(node) && node.body && !(checkGetterContainsSingleThrowStatement(node) || checkGetterReturnsValue(node))) {
error(node.name, Diagnostics.Getters_must_return_a_value);
if (!isInAmbientContext(node) && node.body && !(bodyContainsAReturnStatement(<Block>node.body) || bodyContainsSingleThrowStatement(<Block>node.body))) {
error(node.name, Diagnostics.A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement);
}
}
@ -4877,8 +4923,6 @@ module ts {
}
}
}
// TODO: Check at least one return statement in non-void/any function (except single throw)
}
function checkFunctionDeclaration(node: FunctionDeclaration) {
@ -4890,7 +4934,11 @@ module ts {
if (node === firstDeclaration) {
checkFunctionOrConstructorSymbol(symbol);
}
checkSourceElement(node.body);
if (node.type) {
checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type));
}
// If there is no body and no explicit return type, then report an error.
if (program.getCompilerOptions().noImplicitAny && !node.body && !node.type) {

View file

@ -114,8 +114,9 @@ module ts {
The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2117, category: DiagnosticCategory.Error, key: "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter." },
The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number: { code: 2118, category: DiagnosticCategory.Error, key: "The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'." },
The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2119, category: DiagnosticCategory.Error, key: "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter" },
Getters_must_return_a_value: { code: 2126, category: DiagnosticCategory.Error, key: "Getters must return a value." },
A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2126, category: DiagnosticCategory.Error, key: "A 'get' accessor must return a value or consist of a single 'throw' statement." },
Getter_and_setter_accessors_do_not_agree_in_visibility: { code: 2127, category: DiagnosticCategory.Error, key: "Getter and setter accessors do not agree in visibility." },
A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2131, category: DiagnosticCategory.Error, key: "A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement." },
Untyped_function_calls_may_not_accept_type_arguments: { code: 2158, category: DiagnosticCategory.Error, key: "Untyped function calls may not accept type arguments." },
The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2120, category: DiagnosticCategory.Error, key: "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter." },
The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type: { code: 2121, category: DiagnosticCategory.Error, key: "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type." },

View file

@ -449,7 +449,7 @@
"category": "Error",
"code": 2119
},
"Getters must return a value.": {
"A 'get' accessor must return a value or consist of a single 'throw' statement.": {
"category": "Error",
"code": 2126
},
@ -457,6 +457,10 @@
"category": "Error",
"code": 2127
},
"A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.": {
"category": "Error",
"code": 2131
},
"Untyped function calls may not accept type arguments.": {
"category": "Error",
"code": 2158

View file

@ -1070,7 +1070,7 @@ module ts {
return finishNode(node);
}
function checkIndexSignature(node: SignatureDeclaration, indexerStart: number, indexerLength: number): boolean {
function checkIndexSignature(node: SignatureDeclaration, indexerStart: number, indexerLength: number): void {
var parameter = node.parameters[0];
if (node.parameters.length !== 1) {
var arityDiagnostic = Diagnostics.An_index_signature_must_have_exactly_one_parameter

View file

@ -1,5 +1,7 @@
==== tests/cases/compiler/ParameterList5.ts (2 errors) ====
==== tests/cases/compiler/ParameterList5.ts (3 errors) ====
function A(): (public B) => C {
~~~~~~~~~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~~~~~~~~
!!! A parameter property is only allowed in a constructor implementation.
~

View file

@ -1,9 +1,11 @@
==== tests/cases/compiler/ambientGetters.ts (2 errors) ====
==== tests/cases/compiler/ambientGetters.ts (3 errors) ====
declare class A {
get length() : number;
~
!!! '{' expected.
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
}
declare class B {

View file

@ -1,8 +1,12 @@
==== tests/cases/compiler/conflictingTypeAnnotatedVar.ts (2 errors) ====
==== tests/cases/compiler/conflictingTypeAnnotatedVar.ts (4 errors) ====
var foo: string;
function foo(): number { }
~~~
!!! Duplicate identifier 'foo'.
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function foo(): number { }
~~~
!!! Duplicate identifier 'foo'.
!!! Duplicate identifier 'foo'.
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.

View file

@ -1,7 +1,9 @@
==== tests/cases/compiler/errorOnContextuallyTypedReturnType.ts (1 errors) ====
==== tests/cases/compiler/errorOnContextuallyTypedReturnType.ts (2 errors) ====
var n1: () => boolean = function () { }; // expect an error here
~~
!!! Type '() => void' is not assignable to type '() => boolean':
!!! Type 'void' is not assignable to type 'boolean'.
var n2: () => boolean = function ():boolean { }; // expect an error here
~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.

View file

@ -1,4 +1,4 @@
==== tests/cases/conformance/functions/functionImplementationErrors.ts (6 errors) ====
==== tests/cases/conformance/functions/functionImplementationErrors.ts (7 errors) ====
// FunctionExpression with no return type annotation with multiple return statements with unrelated types
var f1 = function () {
~~~~~~~~~~~~~
@ -47,6 +47,8 @@
// Function implemetnation with non -void return type annotation with no return
function f5(): number {
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
}
var m;

View file

@ -0,0 +1,8 @@
==== tests/cases/compiler/functionWithThrowButNoReturn1.ts (1 errors) ====
function fn(): number {
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
throw new Error('NYI');
var t;
}

View file

@ -0,0 +1,129 @@
==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts (5 errors) ====
function f1(): string {
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
// errors because there are no return statements
}
function f2(): string {
// Permissible; returns undefined.
return;
}
function f3(): string {
return "Okay, because this is a return expression.";
}
function f4(): void {
// Fine since we are typed void.
}
function f5(): void {
// Fine since we are typed void.
return;
}
function f6(): void {
// Fine since we are typed void and return undefined
return undefined;
}
function f7(): void {
// Fine since we are typed void and return null
return null;
}
function f8(): void {
// Fine since are typed any.
return;
}
function f9(): void {
// Fine since we are typed any and return undefined
return undefined;
}
function f10(): void {
// Fine since we are typed any and return null
return null;
}
function f11(): string {
// Fine since we consist of a single throw statement.
throw undefined;
}
function f12(): void {
// Fine since we consist of a single throw statement.
throw undefined;
}
function f13(): any {
// Fine since we consist of a single throw statement.
throw undefined;
}
function f14(): number {
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
// Not fine, since we can *only* consist of a single throw statement
// if no return statements are present but we are annotated.
throw undefined;
throw null;
}
function f15(): number {
// Fine, since we have a return statement somewhere.
throw undefined;
throw null;
return;
}
function f16() {
// Okay; not type annotated.
}
function f17() {
// Okay; not type annotated.
return;
}
function f18() {
return "Okay, not type annotated.";
}
class C {
public get m1() {
~~
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
// Errors; get accessors must return a value.
}
public get m2() {
// Permissible; returns undefined.
return;
}
public get m3() {
return "Okay, because this is a return expression.";
}
public get m4() {
// Fine since this consists of a single throw statement.
throw null;
}
public get m5() {
~~
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
// Not fine, since we can *only* consist of a single throw statement
// if no return statements are present but we are a get accessor.
throw null;
throw undefined.
}
~
!!! Identifier expected.
}

View file

@ -1,8 +1,10 @@
==== tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts (7 errors) ====
==== tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts (8 errors) ====
module TypeScript {
export class MemberName <A,B,C>{
static create<A,B,C>(arg1: any, arg2?: any, arg3?: any): MemberName {
~~~~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~~~~~~~~~~
!!! Generic type 'MemberName<A, B, C>' requires 3 type argument(s).
}
}

View file

@ -4,7 +4,7 @@
~~
!!! Accessors are only available when targeting ECMAScript 5 and higher.
~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
}

View file

@ -1,4 +1,4 @@
==== tests/cases/compiler/gettersAndSettersErrors.ts (9 errors) ====
==== tests/cases/compiler/gettersAndSettersErrors.ts (10 errors) ====
class C {
public get Foo() { return "foo";} // ok
~~~
@ -16,6 +16,8 @@
public set Goo(v:string):string {} // error - setters must not specify a return type
~~~
!!! Accessors are only available when targeting ECMAScript 5 and higher.
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
}
class E {

View file

@ -26,7 +26,7 @@
~~~
!!! Duplicate identifier 'pgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
public psF(param:any) { }
~~~~~~
!!! '{' expected.
@ -40,7 +40,7 @@
~~~
!!! Duplicate identifier 'rgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
private rsF(param:any) { }
~~~~~~~
!!! '{' expected.
@ -62,7 +62,7 @@
~~~
!!! Duplicate identifier 'tgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
~
!!! '{' expected.
@ -128,7 +128,7 @@
~~~
!!! Duplicate identifier 'pgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
public psF(param:any) { }
~~~~~~
!!! '{' expected.
@ -142,7 +142,7 @@
~~~
!!! Duplicate identifier 'rgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
private rsF(param:any) { }
~~~~~~~
!!! '{' expected.
@ -164,7 +164,7 @@
~~~
!!! Duplicate identifier 'tgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
~
!!! '{' expected.
@ -247,7 +247,7 @@
~~~
!!! Duplicate identifier 'pgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
public psF(param:any) { }
~~~~~~
!!! '{' expected.
@ -261,7 +261,7 @@
~~~
!!! Duplicate identifier 'rgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
private rsF(param:any) { }
~~~~~~~
!!! '{' expected.
@ -283,7 +283,7 @@
~~~
!!! Duplicate identifier 'tgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
~
!!! '{' expected.
@ -456,7 +456,7 @@
~~~
!!! Duplicate identifier 'pgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
public psF(param:any) { }
~~~~~~
!!! '{' expected.
@ -470,7 +470,7 @@
~~~
!!! Duplicate identifier 'rgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
private rsF(param:any) { }
~~~~~~~
!!! '{' expected.
@ -492,7 +492,7 @@
~~~
!!! Duplicate identifier 'tgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
~
!!! '{' expected.
@ -558,7 +558,7 @@
~~~
!!! Duplicate identifier 'pgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
public psF(param:any) { }
~~~~~~
!!! '{' expected.
@ -572,7 +572,7 @@
~~~
!!! Duplicate identifier 'rgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
private rsF(param:any) { }
~~~~~~~
!!! '{' expected.
@ -594,7 +594,7 @@
~~~
!!! Duplicate identifier 'tgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
~
!!! '{' expected.
@ -677,7 +677,7 @@
~~~
!!! Duplicate identifier 'pgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
public psF(param:any) { }
~~~~~~
!!! '{' expected.
@ -691,7 +691,7 @@
~~~
!!! Duplicate identifier 'rgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
private rsF(param:any) { }
~~~~~~~
!!! '{' expected.
@ -713,7 +713,7 @@
~~~
!!! Duplicate identifier 'tgF'.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}
~
!!! '{' expected.

View file

@ -1,9 +1,17 @@
==== tests/cases/conformance/statements/returnStatements/invalidReturnStatements.ts (2 errors) ====
==== tests/cases/conformance/statements/returnStatements/invalidReturnStatements.ts (6 errors) ====
// all the following should be error
function fn1(): number { }
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function fn2(): string { }
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function fn3(): boolean { }
~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function fn4(): Date { }
~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function fn7(): any { } // should be valid: any includes void
interface I { id: number }

View file

@ -0,0 +1,10 @@
==== tests/cases/compiler/missingReturnStatement.ts (1 errors) ====
module Test {
export class Bug {
public foo():string {
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
}
}
}

View file

@ -0,0 +1,9 @@
==== tests/cases/compiler/missingReturnStatement1.ts (1 errors) ====
class Foo {
foo(): number {
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
//return 4;
}
}

View file

@ -1,10 +1,15 @@
==== tests/cases/compiler/multiLineErrors.ts (1 errors) ====
==== tests/cases/compiler/multiLineErrors.ts (2 errors) ====
var t = 32;
function noReturn(): {
~
n: string;
~~~~~~~~~~~~~~
y: number;
~~~~~~~~~~~~~~
}
~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
{
var x = 4;
var y = 10;

View file

@ -2,5 +2,5 @@
class C {
get Foo() { }
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -1,4 +1,4 @@
==== tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors3.ts (1 errors) ====
var v = { get Foo() { } };
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.

View file

@ -3,4 +3,4 @@
~~~
!!! A 'get' accessor cannot have parameters.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.

View file

@ -4,5 +4,5 @@
~~~
!!! Accessors are only available when targeting ECMAScript 5 and higher.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -3,4 +3,4 @@
~~~
!!! Accessors are only available when targeting ECMAScript 5 and higher.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.

View file

@ -1,9 +1,13 @@
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block3.ts (1 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block3.ts (3 errors) ====
class C {
private a(): boolean {
~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
private b(): boolean {
~~~~~~~
!!! Statement expected.
~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
}
}

View file

@ -1,4 +1,4 @@
==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts (9 errors) ====
==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts (10 errors) ====
class C extends A<T> implements B<T> {
~~~~
!!! Cannot find name 'A'.
@ -30,6 +30,8 @@
function f2(): F<T> {
~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~~~~
!!! Cannot find name 'F'.
}

View file

@ -1,4 +1,4 @@
==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts (9 errors) ====
==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts (10 errors) ====
class C extends A<X<T>, Y<Z<T>>> implements B<X<T>, Y<Z<T>>> {
~~~~~~~~~~~~~~~~
!!! Cannot find name 'A'.
@ -30,6 +30,8 @@
function f2(): F<X<T>, Y<Z<T>>> {
~~~~~~~~~~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~~~~~~~~~~~~~~~~
!!! Cannot find name 'F'.
}

View file

@ -4,5 +4,5 @@
~~~
!!! An accessor cannot have type parameters.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -2,6 +2,6 @@
class C {
get foo() { }
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
set foo(a) { }
}

View file

@ -2,5 +2,5 @@
class C {
get a() { }
~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -4,5 +4,5 @@
~~~~~~
!!! 'export' modifier cannot appear on a class element.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -4,5 +4,5 @@
~~~
!!! A 'get' accessor cannot have parameters.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -2,5 +2,5 @@
class C {
get "b"() { }
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -2,5 +2,5 @@
class C {
get 0() { }
~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -4,5 +4,5 @@
~~~~~~
!!! Accessibility modifier already seen.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -4,5 +4,5 @@
~~~~~~
!!! 'static' modifier already seen.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -4,5 +4,5 @@
~~~~~~
!!! 'public' modifier must precede 'static' modifier.
~~~
!!! Getters must return a value.
!!! A 'get' accessor must return a value or consist of a single 'throw' statement.
}

View file

@ -1,5 +1,7 @@
==== tests/cases/conformance/parser/ecmascript5/ParameterLists/parserParameterList5.ts (2 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ParameterLists/parserParameterList5.ts (3 errors) ====
function A(): (public B) => C {
~~~~~~~~~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~~~~~~~~
!!! A parameter property is only allowed in a constructor implementation.
~

View file

@ -1,7 +1,9 @@
==== tests/cases/conformance/parser/ecmascript5/Accessors/parserSetAccessorWithTypeAnnotation1.ts (1 errors) ====
==== tests/cases/conformance/parser/ecmascript5/Accessors/parserSetAccessorWithTypeAnnotation1.ts (2 errors) ====
class C {
set foo(v): number {
~~~
!!! A 'set' accessor cannot have a return type annotation.
~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
}
}

View file

@ -1,4 +1,4 @@
==== tests/cases/compiler/recursiveFunctionTypes.ts (10 errors) ====
==== tests/cases/compiler/recursiveFunctionTypes.ts (12 errors) ====
function fn(): typeof fn { return 1; }
~
!!! Type 'number' is not assignable to type '() => typeof fn'.
@ -17,7 +17,11 @@
function f1(d: typeof f1) { }
function f2(): typeof g2 { }
~~~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function g2(): typeof f2 { }
~~~~~~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
interface I<T> { }
function f3(): I<typeof f3> { return f3; }

View file

@ -1,5 +1,7 @@
==== tests/cases/compiler/returnTypeParameter.ts (1 errors) ====
==== tests/cases/compiler/returnTypeParameter.ts (2 errors) ====
function f<T>(a: T): T { } // error, no return statement
~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
function f2<T>(a: T): T { return T; } // bug was that this satisfied the return statement requirement
~
!!! Cannot find name 'T'.

View file

@ -1,4 +1,4 @@
==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts (25 errors) ====
==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts (29 errors) ====
// Type parameters are in scope in their own and other type parameter lists
// Some negative cases
@ -35,9 +35,13 @@
~~~~~~~~~~~
!!! Constraint of a type parameter cannot reference any type parameter from the same type parameter list.
~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~
!!! Cannot find name 'V'.
function bar<V extends T, W extends U>(): X { // error
~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~
!!! Cannot find name 'X'.
function baz<X extends W, Y extends V>(a: X, b: Y): T {
x = y;
@ -54,9 +58,13 @@
~~~~~~~~~~~
!!! Constraint of a type parameter cannot reference any type parameter from the same type parameter list.
~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~
!!! Cannot find name 'W'.
function bar<V extends T, W extends U>(): Y { // error
~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~
!!! Cannot find name 'Y'.
function baz<X extends W, Y extends V>(a: X, b: Y): T {
x = y;

View file

@ -1,4 +1,4 @@
==== tests/cases/compiler/unknownSymbols1.ts (13 errors) ====
==== tests/cases/compiler/unknownSymbols1.ts (14 errors) ====
var x = asdf;
~~~~
!!! Cannot find name 'asdf'.
@ -10,6 +10,8 @@
~~~~
!!! Cannot find name 'asdf'.
~~~~
!!! A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.
~~~~
!!! Cannot find name 'asdf'.
function foo2() {
return asdf;

View file

@ -0,0 +1,119 @@
// @target: es5
function f1(): string {
// errors because there are no return statements
}
function f2(): string {
// Permissible; returns undefined.
return;
}
function f3(): string {
return "Okay, because this is a return expression.";
}
function f4(): void {
// Fine since we are typed void.
}
function f5(): void {
// Fine since we are typed void.
return;
}
function f6(): void {
// Fine since we are typed void and return undefined
return undefined;
}
function f7(): void {
// Fine since we are typed void and return null
return null;
}
function f8(): void {
// Fine since are typed any.
return;
}
function f9(): void {
// Fine since we are typed any and return undefined
return undefined;
}
function f10(): void {
// Fine since we are typed any and return null
return null;
}
function f11(): string {
// Fine since we consist of a single throw statement.
throw undefined;
}
function f12(): void {
// Fine since we consist of a single throw statement.
throw undefined;
}
function f13(): any {
// Fine since we consist of a single throw statement.
throw undefined;
}
function f14(): number {
// Not fine, since we can *only* consist of a single throw statement
// if no return statements are present but we are annotated.
throw undefined;
throw null;
}
function f15(): number {
// Fine, since we have a return statement somewhere.
throw undefined;
throw null;
return;
}
function f16() {
// Okay; not type annotated.
}
function f17() {
// Okay; not type annotated.
return;
}
function f18() {
return "Okay, not type annotated.";
}
class C {
public get m1() {
// Errors; get accessors must return a value.
}
public get m2() {
// Permissible; returns undefined.
return;
}
public get m3() {
return "Okay, because this is a return expression.";
}
public get m4() {
// Fine since this consists of a single throw statement.
throw null;
}
public get m5() {
// Not fine, since we can *only* consist of a single throw statement
// if no return statements are present but we are a get accessor.
throw null;
throw undefined.
}
}