@@ -4524,25 +4524,26 @@ module ts {
4524
4524
}
4525
4525
}
4526
4526
}
4527
+ checkSignatureDeclaration ( node ) ;
4527
4528
}
4528
4529
}
4529
- if ( fullTypeCheck && ! ( links . flags & NodeCheckFlags . TypeChecked ) ) {
4530
- checkSignatureDeclaration ( node ) ;
4530
+ return type ;
4531
+ }
4532
+
4533
+ function checkFunctionExpressionBody ( node : FunctionExpression ) {
4534
+ if ( node . type ) {
4535
+ checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment ( node , getTypeFromTypeNode ( node . type ) ) ;
4536
+ }
4537
+ if ( node . body . kind === SyntaxKind . FunctionBlock ) {
4538
+ checkSourceElement ( node . body ) ;
4539
+ }
4540
+ else {
4541
+ var exprType = checkExpression ( node . body ) ;
4531
4542
if ( node . type ) {
4532
- checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment ( node , getTypeFromTypeNode ( node . type ) ) ;
4533
- }
4534
- if ( node . body . kind === SyntaxKind . FunctionBlock ) {
4535
- checkSourceElement ( node . body ) ;
4543
+ checkTypeAssignableTo ( exprType , getTypeFromTypeNode ( node . type ) , node . body , undefined , undefined ) ;
4536
4544
}
4537
- else {
4538
- var exprType = checkExpression ( node . body ) ;
4539
- if ( node . type ) {
4540
- checkTypeAssignableTo ( exprType , getTypeFromTypeNode ( node . type ) , node . body , undefined , undefined ) ;
4541
- }
4542
- }
4543
- links . flags |= NodeCheckFlags . TypeChecked ;
4545
+ checkFunctionExpressionBodies ( node . body ) ;
4544
4546
}
4545
- return type ;
4546
4547
}
4547
4548
4548
4549
function checkArithmeticOperandType ( operand : Node , type : Type , diagnostic : DiagnosticMessage ) : boolean {
@@ -6414,9 +6415,10 @@ module ts {
6414
6415
case SyntaxKind . FunctionDeclaration :
6415
6416
return checkFunctionDeclaration ( < FunctionDeclaration > node ) ;
6416
6417
case SyntaxKind . Block :
6418
+ return checkBlock ( < Block > node ) ;
6417
6419
case SyntaxKind . FunctionBlock :
6418
6420
case SyntaxKind . ModuleBlock :
6419
- return checkBlock ( < Block > node ) ;
6421
+ return checkBody ( < Block > node ) ;
6420
6422
case SyntaxKind . VariableStatement :
6421
6423
return checkVariableStatement ( < VariableStatement > node ) ;
6422
6424
case SyntaxKind . ExpressionStatement :
@@ -6463,13 +6465,91 @@ module ts {
6463
6465
}
6464
6466
}
6465
6467
6468
+ // Function expression bodies are checked after all statements in the enclosing body. This is to ensure
6469
+ // constructs like the following are permitted:
6470
+ // var foo = function () {
6471
+ // var s = foo();
6472
+ // return "hello";
6473
+ // }
6474
+ // Here, performing a full type check of the body of the function expression whilst in the process of
6475
+ // determining the type of foo would cause foo to be given type any because of the recursive reference.
6476
+ // Delaying the type check of the body ensures foo has been assigned a type.
6477
+ function checkFunctionExpressionBodies ( node : Node ) : void {
6478
+ switch ( node . kind ) {
6479
+ case SyntaxKind . FunctionExpression :
6480
+ case SyntaxKind . ArrowFunction :
6481
+ forEach ( ( < FunctionDeclaration > node ) . parameters , checkFunctionExpressionBodies ) ;
6482
+ checkFunctionExpressionBody ( < FunctionExpression > node ) ;
6483
+ break ;
6484
+ case SyntaxKind . Method :
6485
+ case SyntaxKind . Constructor :
6486
+ case SyntaxKind . GetAccessor :
6487
+ case SyntaxKind . SetAccessor :
6488
+ case SyntaxKind . FunctionDeclaration :
6489
+ forEach ( ( < FunctionDeclaration > node ) . parameters , checkFunctionExpressionBodies ) ;
6490
+ break ;
6491
+ case SyntaxKind . WithStatement :
6492
+ checkFunctionExpressionBodies ( ( < WithStatement > node ) . expression ) ;
6493
+ break ;
6494
+ case SyntaxKind . Parameter :
6495
+ case SyntaxKind . Property :
6496
+ case SyntaxKind . ArrayLiteral :
6497
+ case SyntaxKind . ObjectLiteral :
6498
+ case SyntaxKind . PropertyAssignment :
6499
+ case SyntaxKind . PropertyAccess :
6500
+ case SyntaxKind . IndexedAccess :
6501
+ case SyntaxKind . CallExpression :
6502
+ case SyntaxKind . NewExpression :
6503
+ case SyntaxKind . TypeAssertion :
6504
+ case SyntaxKind . ParenExpression :
6505
+ case SyntaxKind . PrefixOperator :
6506
+ case SyntaxKind . PostfixOperator :
6507
+ case SyntaxKind . BinaryExpression :
6508
+ case SyntaxKind . ConditionalExpression :
6509
+ case SyntaxKind . Block :
6510
+ case SyntaxKind . FunctionBlock :
6511
+ case SyntaxKind . ModuleBlock :
6512
+ case SyntaxKind . VariableStatement :
6513
+ case SyntaxKind . ExpressionStatement :
6514
+ case SyntaxKind . IfStatement :
6515
+ case SyntaxKind . DoStatement :
6516
+ case SyntaxKind . WhileStatement :
6517
+ case SyntaxKind . ForStatement :
6518
+ case SyntaxKind . ForInStatement :
6519
+ case SyntaxKind . ContinueStatement :
6520
+ case SyntaxKind . BreakStatement :
6521
+ case SyntaxKind . ReturnStatement :
6522
+ case SyntaxKind . SwitchStatement :
6523
+ case SyntaxKind . CaseClause :
6524
+ case SyntaxKind . DefaultClause :
6525
+ case SyntaxKind . LabelledStatement :
6526
+ case SyntaxKind . ThrowStatement :
6527
+ case SyntaxKind . TryStatement :
6528
+ case SyntaxKind . TryBlock :
6529
+ case SyntaxKind . CatchBlock :
6530
+ case SyntaxKind . FinallyBlock :
6531
+ case SyntaxKind . VariableDeclaration :
6532
+ case SyntaxKind . ClassDeclaration :
6533
+ case SyntaxKind . EnumDeclaration :
6534
+ case SyntaxKind . EnumMember :
6535
+ case SyntaxKind . SourceFile :
6536
+ forEachChild ( node , checkFunctionExpressionBodies ) ;
6537
+ break ;
6538
+ }
6539
+ }
6540
+
6541
+ function checkBody ( node : Block ) {
6542
+ checkBlock ( node ) ;
6543
+ checkFunctionExpressionBodies ( node ) ;
6544
+ }
6545
+
6466
6546
// Fully type check a source file and collect the relevant diagnostics.
6467
6547
function checkSourceFile ( node : SourceFile ) {
6468
6548
var links = getNodeLinks ( node ) ;
6469
6549
if ( ! ( links . flags & NodeCheckFlags . TypeChecked ) ) {
6470
6550
emitExtends = false ;
6471
6551
potentialThisCollisions . length = 0 ;
6472
- forEach ( node . statements , checkSourceElement ) ;
6552
+ checkBody ( node ) ;
6473
6553
if ( isExternalModule ( node ) ) {
6474
6554
var symbol = getExportAssignmentSymbol ( node . symbol ) ;
6475
6555
if ( symbol && symbol . flags & SymbolFlags . Import ) {
0 commit comments