Move return checks to the grammar checker.

This commit is contained in:
Cyrus Najmabadi 2014-11-19 15:30:35 -08:00
parent cd75243d83
commit b9353086a4
8 changed files with 61 additions and 79 deletions

View file

@ -835,7 +835,6 @@ module ts {
var lookAheadMode = LookAheadMode.NotLookingAhead;
var inAmbientContext = false;
var inFunctionBody = false;
function getLineStarts(): number[] {
return lineStarts || (lineStarts = computeLineStarts(sourceText));
@ -2062,7 +2061,7 @@ module ts {
var body: Node;
if (token === SyntaxKind.OpenBraceToken) {
body = parseBody(/* ignoreMissingOpenBrace */ false);
body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false);
}
else if (isStatement(/* inErrorRecovery */ true) && !isStartOfExpressionStatement() && token !== SyntaxKind.FunctionKeyword) {
// Check if we got a plain statement (i.e. no expression-statements, no functions expressions/declarations)
@ -2079,7 +2078,7 @@ module ts {
// up preemptively closing the containing construct.
//
// Note: even when 'ignoreMissingOpenBrace' is passed as true, parseBody will still error.
body = parseBody(/* ignoreMissingOpenBrace */ true);
body = parseFunctionBlock(/* ignoreMissingOpenBrace */ true);
}
else {
body = parseAssignmentExpression(noIn);
@ -2431,7 +2430,7 @@ module ts {
node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
node.name = propertyName;
var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false);
var body = parseBody(/* ignoreMissingOpenBrace */ false);
var body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false);
// do not propagate property name as name for function expression
// for scenarios like
// var x = 1;
@ -2492,7 +2491,7 @@ module ts {
parseExpected(SyntaxKind.FunctionKeyword);
var name = isIdentifier() ? parseIdentifier() : undefined;
var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false);
var body = parseBody(/* ignoreMissingOpenBrace */ false);
var body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false);
return makeFunctionExpression(SyntaxKind.FunctionExpression, pos, name, sig, body);
}
@ -2530,13 +2529,9 @@ module ts {
return finishNode(node);
}
function parseBody(ignoreMissingOpenBrace: boolean): Block {
var saveInFunctionBody = inFunctionBody;
inFunctionBody = true;
function parseFunctionBlock(ignoreMissingOpenBrace: boolean): Block {
var block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true);
block.kind = SyntaxKind.FunctionBlock;
inFunctionBody = saveInFunctionBody;
return block;
}
@ -2660,18 +2655,15 @@ module ts {
function parseReturnStatement(): ReturnStatement {
var node = <ReturnStatement>createNode(SyntaxKind.ReturnStatement);
var errorCountBeforeReturnStatement = file.parseDiagnostics.length;
var returnTokenStart = scanner.getTokenPos();
var returnTokenLength = scanner.getTextPos() - returnTokenStart;
parseExpected(SyntaxKind.ReturnKeyword);
if (!canParseSemicolon()) node.expression = parseExpression();
parseSemicolon();
// In an ambient context, we will already give an error for having a statement.
if (!inFunctionBody && !inAmbientContext && errorCountBeforeReturnStatement === file.parseDiagnostics.length) {
grammarErrorAtPos(returnTokenStart, returnTokenLength, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body);
if (!canParseSemicolon()) {
node.expression = parseExpression();
}
parseSemicolon();
return finishNode(node);
}
@ -2914,7 +2906,7 @@ module ts {
function parseFunctionBlockOrSemicolon(): Block {
if (token === SyntaxKind.OpenBraceToken) {
return parseBody(/* ignoreMissingOpenBrace */ false);
return parseFunctionBlock(/* ignoreMissingOpenBrace */ false);
}
if (canParseSemicolon()) {
@ -3045,7 +3037,7 @@ module ts {
node.body = <Block>createMissingNode();
}
else {
node.body = parseBody(/* ignoreMissingOpenBrace */ false);
node.body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false);
}
return finishNode(node);
@ -3293,7 +3285,6 @@ module ts {
if (parseOptional(SyntaxKind.ImplementsKeyword)) {
node.implementedTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, parseTypeReference);
}
var errorCountBeforeClassBody = file.parseDiagnostics.length;
if (parseExpected(SyntaxKind.OpenBraceToken)) {
node.members = parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassMemberDeclaration);
parseExpected(SyntaxKind.CloseBraceToken);
@ -3700,6 +3691,7 @@ module ts {
// We're automatically in an ambient context if this is a .d.ts file.
var inAmbientContext = fileExtensionIs(file.filename, ".d.ts");
var inFunctionBlock = false;
var parent: Node;
visitNode(file);
@ -3709,6 +3701,11 @@ module ts {
node.parent = parent;
parent = node;
var savedInFunctionBlock = inFunctionBlock;
if (node.kind === SyntaxKind.FunctionBlock) {
inFunctionBlock = true;
}
var savedInAmbientContext = inAmbientContext
if (node.flags & NodeFlags.Ambient) {
inAmbientContext = true;
@ -3717,6 +3714,7 @@ module ts {
checkNode(node);
inAmbientContext = savedInAmbientContext;
inFunctionBlock = savedInFunctionBlock;
parent = savedParent;
}
@ -3724,7 +3722,7 @@ module ts {
// First, check if you have a statement in a place where it is not allowed. We want
// to do this before recursing, because we'd prefer to report these errors at the top
// level instead of at some nested level.
if (checkForStatementInAmbientContext(node)) {
if (inAmbientContext && checkForStatementInAmbientContext(node)) {
return;
}
@ -3772,6 +3770,7 @@ module ts {
case SyntaxKind.PostfixOperator: return visitPostfixOperator(<UnaryExpression>node);
case SyntaxKind.PrefixOperator: return visitPrefixOperator(<UnaryExpression>node);
case SyntaxKind.PropertyAssignment: return visitPropertyAssignment(<PropertyDeclaration>node);
case SyntaxKind.ReturnStatement: return visitReturnStatement(<ReturnStatement>node);
case SyntaxKind.SetAccessor: return visitSetAccessor(<MethodDeclaration>node);
case SyntaxKind.ShorthandPropertyAssignment: return visitShorthandPropertyAssignment(<ShortHandPropertyDeclaration>node);
case SyntaxKind.SwitchStatement: return visitSwitchStatement(<SwitchStatement>node);
@ -3814,27 +3813,25 @@ module ts {
}
function checkForStatementInAmbientContext(node: Node): boolean {
if (inAmbientContext) {
switch (node.kind) {
case SyntaxKind.Block:
case SyntaxKind.EmptyStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ContinueStatement:
case SyntaxKind.BreakStatement:
case SyntaxKind.ReturnStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.TryStatement:
case SyntaxKind.DebuggerStatement:
case SyntaxKind.LabeledStatement:
case SyntaxKind.ExpressionStatement:
return grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
}
switch (node.kind) {
case SyntaxKind.Block:
case SyntaxKind.EmptyStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ContinueStatement:
case SyntaxKind.BreakStatement:
case SyntaxKind.ReturnStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.TryStatement:
case SyntaxKind.DebuggerStatement:
case SyntaxKind.LabeledStatement:
case SyntaxKind.ExpressionStatement:
return grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
}
}
@ -4362,6 +4359,12 @@ module ts {
}
}
function visitReturnStatement(node: ReturnStatement) {
if (!inFunctionBlock) {
grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body);
}
}
function visitSetAccessor(node: MethodDeclaration) {
checkTypeParameterList(node.typeParameters) ||
checkParameterList(node.parameters) ||

View file

@ -7,14 +7,11 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(28,30): error TS
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(28,33): error TS1138: Parameter declaration expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(28,34): error TS1005: ';' expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(28,36): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(30,21): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(31,18): error TS1129: Statement expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(38,17): error TS1109: Expression expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(40,41): error TS1005: ';' expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(40,45): error TS1002: Unterminated string literal.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(43,21): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(46,13): error TS1005: 'try' expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(55,13): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(58,5): error TS1128: Declaration or statement expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(69,13): error TS1109: Expression expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(72,37): error TS1127: Invalid character.
@ -35,10 +32,8 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(234,14): error T
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(235,9): error TS1128: Declaration or statement expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(235,27): error TS1005: ',' expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(235,36): error TS1005: ';' expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(236,13): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(238,9): error TS1128: Declaration or statement expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(238,26): error TS1005: ';' expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(239,13): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(241,5): error TS1128: Declaration or statement expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(254,69): error TS1110: Type expected.
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(256,9): error TS1128: Declaration or statement expected.
@ -93,7 +88,7 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,29): error T
tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error TS2304: Cannot find name 'string'.
==== tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts (93 errors) ====
==== tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts (88 errors) ====
declare module "fs" {
export class File {
constructor(filename: string);
@ -153,8 +148,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error T
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
return 1;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
^
~
!!! error TS1129: Statement expected.
@ -188,8 +181,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error T
!!! error TS2304: Cannot find name 'retValue'.
return 1;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}
}
catch (e) {
@ -208,8 +199,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error T
!!! error TS2304: Cannot find name 'console'.
return 0;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}
}
@ -453,8 +442,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error T
~~~~~~
!!! error TS2304: Cannot find name 'number'.
return val;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}
public method2() {
~~~~~~
@ -464,8 +451,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error T
~~~~~~~
!!! error TS2304: Cannot find name 'method2'.
return 2 * this.method1(2);
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}
}
~

View file

@ -1,11 +1,10 @@
tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts(13,13): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts(13,13): error TS1131: Property or signature expected.
tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts(14,9): error TS1128: Declaration or statement expected.
tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts(15,5): error TS1128: Declaration or statement expected.
tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts(11,5): error TS2411: Property 'a' of type '{ toString: () => {}; }' is not assignable to string index type 'Object'.
==== tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts (5 errors) ====
==== tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtendingClass2.ts (4 errors) ====
class Foo {
x: string;
y() { }
@ -23,8 +22,6 @@ tests/cases/conformance/interfaces/interfacesExtendingClasses/interfaceExtending
!!! error TS2411: Property 'a' of type '{ toString: () => {}; }' is not assignable to string index type 'Object'.
return 1;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
~~~~~~
!!! error TS1131: Property or signature expected.
};
~

View file

@ -1,13 +1,10 @@
tests/cases/compiler/overloadOnConstAsTypeAnnotation.ts(1,37): error TS1005: ';' expected.
tests/cases/compiler/overloadOnConstAsTypeAnnotation.ts(1,42): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/overloadOnConstAsTypeAnnotation.ts(1,8): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
==== tests/cases/compiler/overloadOnConstAsTypeAnnotation.ts (3 errors) ====
==== tests/cases/compiler/overloadOnConstAsTypeAnnotation.ts (2 errors) ====
var f: (x: 'hi') => number = ('hi') => { return 1; };
~~
!!! error TS1005: ';' expected.
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
~~~~~~~~~~~~~~~~~~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.

View file

@ -1,19 +1,13 @@
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts(1,1): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts(2,1): error TS1128: Declaration or statement expected.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts(3,1): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts(4,1): error TS1128: Declaration or statement expected.
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts (4 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts (2 errors) ====
return foo;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}
~
!!! error TS1128: Declaration or statement expected.
return bar;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}
~
!!! error TS1128: Declaration or statement expected.

View file

@ -1,8 +1,11 @@
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserErrorRecovery_VariableList1.ts(1,6): error TS1009: Trailing comma not allowed.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserErrorRecovery_VariableList1.ts(2,1): error TS1108: A 'return' statement can only be used within a function body.
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserErrorRecovery_VariableList1.ts (1 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserErrorRecovery_VariableList1.ts (2 errors) ====
var a,
~
!!! error TS1009: Trailing comma not allowed.
return;
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.

View file

@ -2,14 +2,13 @@ tests/cases/compiler/propertyWrappedInTry.ts(3,5): error TS1068: Unexpected toke
tests/cases/compiler/propertyWrappedInTry.ts(5,9): error TS1129: Statement expected.
tests/cases/compiler/propertyWrappedInTry.ts(11,5): error TS1128: Declaration or statement expected.
tests/cases/compiler/propertyWrappedInTry.ts(11,18): error TS1005: ';' expected.
tests/cases/compiler/propertyWrappedInTry.ts(13,9): error TS1108: A 'return' statement can only be used within a function body.
tests/cases/compiler/propertyWrappedInTry.ts(17,1): error TS1128: Declaration or statement expected.
tests/cases/compiler/propertyWrappedInTry.ts(5,16): error TS2304: Cannot find name 'bar'.
tests/cases/compiler/propertyWrappedInTry.ts(5,22): error TS2304: Cannot find name 'someInitThatMightFail'.
tests/cases/compiler/propertyWrappedInTry.ts(11,12): error TS2304: Cannot find name 'baz'.
==== tests/cases/compiler/propertyWrappedInTry.ts (9 errors) ====
==== tests/cases/compiler/propertyWrappedInTry.ts (8 errors) ====
class Foo {
try {
@ -37,8 +36,6 @@ tests/cases/compiler/propertyWrappedInTry.ts(11,12): error TS2304: Cannot find n
!!! error TS2304: Cannot find name 'baz'.
return this.bar; // doesn't get rewritten to Foo.bar.
~~~~~~
!!! error TS1108: A 'return' statement can only be used within a function body.
}

View file

@ -1,7 +1,9 @@
tests/cases/compiler/switchStatementsWithMultipleDefaults.ts(9,5): error TS1113: A 'default' clause cannot appear more than once in a 'switch' statement.
tests/cases/compiler/switchStatementsWithMultipleDefaults.ts(10,5): error TS1113: A 'default' clause cannot appear more than once in a 'switch' statement.
tests/cases/compiler/switchStatementsWithMultipleDefaults.ts(28,22): error TS1108: A 'return' statement can only be used within a function body.
==== tests/cases/compiler/switchStatementsWithMultipleDefaults.ts (1 errors) ====
==== tests/cases/compiler/switchStatementsWithMultipleDefaults.ts (3 errors) ====
var x = 10;
@ -11,7 +13,11 @@ tests/cases/compiler/switchStatementsWithMultipleDefaults.ts(28,22): error TS110
default: // No issues.
break;
default: // Error; second 'default' clause.
~~~~~~~~
!!! error TS1113: A 'default' clause cannot appear more than once in a 'switch' statement.
default: // Error; third 'default' clause.
~~~~~~~~
!!! error TS1113: A 'default' clause cannot appear more than once in a 'switch' statement.
case 3:
x *= x;
}