@@ -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 {
@@ -6438,9 +6439,10 @@ module ts {
6438
6439
case SyntaxKind . FunctionDeclaration :
6439
6440
return checkFunctionDeclaration ( < FunctionDeclaration > node ) ;
6440
6441
case SyntaxKind . Block :
6442
+ return checkBlock ( < Block > node ) ;
6441
6443
case SyntaxKind . FunctionBlock :
6442
6444
case SyntaxKind . ModuleBlock :
6443
- return checkBlock ( < Block > node ) ;
6445
+ return checkBody ( < Block > node ) ;
6444
6446
case SyntaxKind . VariableStatement :
6445
6447
return checkVariableStatement ( < VariableStatement > node ) ;
6446
6448
case SyntaxKind . ExpressionStatement :
@@ -6487,13 +6489,91 @@ module ts {
6487
6489
}
6488
6490
}
6489
6491
6492
+ // Function expression bodies are checked after all statements in the enclosing body. This is to ensure
6493
+ // constructs like the following are permitted:
6494
+ // var foo = function () {
6495
+ // var s = foo();
6496
+ // return "hello";
6497
+ // }
6498
+ // Here, performing a full type check of the body of the function expression whilst in the process of
6499
+ // determining the type of foo would cause foo to be given type any because of the recursive reference.
6500
+ // Delaying the type check of the body ensures foo has been assigned a type.
6501
+ function checkFunctionExpressionBodies ( node : Node ) : void {
6502
+ switch ( node . kind ) {
6503
+ case SyntaxKind . FunctionExpression :
6504
+ case SyntaxKind . ArrowFunction :
6505
+ forEach ( ( < FunctionDeclaration > node ) . parameters , checkFunctionExpressionBodies ) ;
6506
+ checkFunctionExpressionBody ( < FunctionExpression > node ) ;
6507
+ break ;
6508
+ case SyntaxKind . Method :
6509
+ case SyntaxKind . Constructor :
6510
+ case SyntaxKind . GetAccessor :
6511
+ case SyntaxKind . SetAccessor :
6512
+ case SyntaxKind . FunctionDeclaration :
6513
+ forEach ( ( < FunctionDeclaration > node ) . parameters , checkFunctionExpressionBodies ) ;
6514
+ break ;
6515
+ case SyntaxKind . WithStatement :
6516
+ checkFunctionExpressionBodies ( ( < WithStatement > node ) . expression ) ;
6517
+ break ;
6518
+ case SyntaxKind . Parameter :
6519
+ case SyntaxKind . Property :
6520
+ case SyntaxKind . ArrayLiteral :
6521
+ case SyntaxKind . ObjectLiteral :
6522
+ case SyntaxKind . PropertyAssignment :
6523
+ case SyntaxKind . PropertyAccess :
6524
+ case SyntaxKind . IndexedAccess :
6525
+ case SyntaxKind . CallExpression :
6526
+ case SyntaxKind . NewExpression :
6527
+ case SyntaxKind . TypeAssertion :
6528
+ case SyntaxKind . ParenExpression :
6529
+ case SyntaxKind . PrefixOperator :
6530
+ case SyntaxKind . PostfixOperator :
6531
+ case SyntaxKind . BinaryExpression :
6532
+ case SyntaxKind . ConditionalExpression :
6533
+ case SyntaxKind . Block :
6534
+ case SyntaxKind . FunctionBlock :
6535
+ case SyntaxKind . ModuleBlock :
6536
+ case SyntaxKind . VariableStatement :
6537
+ case SyntaxKind . ExpressionStatement :
6538
+ case SyntaxKind . IfStatement :
6539
+ case SyntaxKind . DoStatement :
6540
+ case SyntaxKind . WhileStatement :
6541
+ case SyntaxKind . ForStatement :
6542
+ case SyntaxKind . ForInStatement :
6543
+ case SyntaxKind . ContinueStatement :
6544
+ case SyntaxKind . BreakStatement :
6545
+ case SyntaxKind . ReturnStatement :
6546
+ case SyntaxKind . SwitchStatement :
6547
+ case SyntaxKind . CaseClause :
6548
+ case SyntaxKind . DefaultClause :
6549
+ case SyntaxKind . LabelledStatement :
6550
+ case SyntaxKind . ThrowStatement :
6551
+ case SyntaxKind . TryStatement :
6552
+ case SyntaxKind . TryBlock :
6553
+ case SyntaxKind . CatchBlock :
6554
+ case SyntaxKind . FinallyBlock :
6555
+ case SyntaxKind . VariableDeclaration :
6556
+ case SyntaxKind . ClassDeclaration :
6557
+ case SyntaxKind . EnumDeclaration :
6558
+ case SyntaxKind . EnumMember :
6559
+ case SyntaxKind . SourceFile :
6560
+ forEachChild ( node , checkFunctionExpressionBodies ) ;
6561
+ break ;
6562
+ }
6563
+ }
6564
+
6565
+ function checkBody ( node : Block ) {
6566
+ checkBlock ( node ) ;
6567
+ checkFunctionExpressionBodies ( node ) ;
6568
+ }
6569
+
6490
6570
// Fully type check a source file and collect the relevant diagnostics.
6491
6571
function checkSourceFile ( node : SourceFile ) {
6492
6572
var links = getNodeLinks ( node ) ;
6493
6573
if ( ! ( links . flags & NodeCheckFlags . TypeChecked ) ) {
6494
6574
emitExtends = false ;
6495
6575
potentialThisCollisions . length = 0 ;
6496
- forEach ( node . statements , checkSourceElement ) ;
6576
+ checkBody ( node ) ;
6497
6577
if ( isExternalModule ( node ) ) {
6498
6578
var symbol = getExportAssignmentSymbol ( node . symbol ) ;
6499
6579
if ( symbol && symbol . flags & SymbolFlags . Import ) {
0 commit comments