Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 96 additions & 16 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4524,25 +4524,26 @@ module ts {
}
}
}
checkSignatureDeclaration(node);
}
}
if (fullTypeCheck && !(links.flags & NodeCheckFlags.TypeChecked)) {
checkSignatureDeclaration(node);
return type;
}

function checkFunctionExpressionBody(node: FunctionExpression) {
if (node.type) {
checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type));
}
if (node.body.kind === SyntaxKind.FunctionBlock) {
checkSourceElement(node.body);
}
else {
var exprType = checkExpression(node.body);
if (node.type) {
checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type));
}
if (node.body.kind === SyntaxKind.FunctionBlock) {
checkSourceElement(node.body);
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, undefined, undefined);
}
else {
var exprType = checkExpression(node.body);
if (node.type) {
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, undefined, undefined);
}
}
links.flags |= NodeCheckFlags.TypeChecked;
checkFunctionExpressionBodies(node.body);
}
return type;
}

function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean {
Expand Down Expand Up @@ -6414,9 +6415,10 @@ module ts {
case SyntaxKind.FunctionDeclaration:
return checkFunctionDeclaration(<FunctionDeclaration>node);
case SyntaxKind.Block:
return checkBlock(<Block>node);
case SyntaxKind.FunctionBlock:
case SyntaxKind.ModuleBlock:
return checkBlock(<Block>node);
return checkBody(<Block>node);
case SyntaxKind.VariableStatement:
return checkVariableStatement(<VariableStatement>node);
case SyntaxKind.ExpressionStatement:
Expand Down Expand Up @@ -6463,13 +6465,91 @@ module ts {
}
}

// Function expression bodies are checked after all statements in the enclosing body. This is to ensure
// constructs like the following are permitted:
// var foo = function () {
// var s = foo();
// return "hello";
// }
// Here, performing a full type check of the body of the function expression whilst in the process of
// determining the type of foo would cause foo to be given type any because of the recursive reference.
// Delaying the type check of the body ensures foo has been assigned a type.
function checkFunctionExpressionBodies(node: Node): void {
switch (node.kind) {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
forEach((<FunctionDeclaration>node).parameters, checkFunctionExpressionBodies);
checkFunctionExpressionBody(<FunctionExpression>node);
break;
case SyntaxKind.Method:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
forEach((<FunctionDeclaration>node).parameters, checkFunctionExpressionBodies);
break;
case SyntaxKind.WithStatement:
checkFunctionExpressionBodies((<WithStatement>node).expression);
break;
case SyntaxKind.Parameter:
case SyntaxKind.Property:
case SyntaxKind.ArrayLiteral:
case SyntaxKind.ObjectLiteral:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.PropertyAccess:
case SyntaxKind.IndexedAccess:
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.TypeAssertion:
case SyntaxKind.ParenExpression:
case SyntaxKind.PrefixOperator:
case SyntaxKind.PostfixOperator:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.Block:
case SyntaxKind.FunctionBlock:
case SyntaxKind.ModuleBlock:
case SyntaxKind.VariableStatement:
case SyntaxKind.ExpressionStatement:
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.SwitchStatement:
case SyntaxKind.CaseClause:
case SyntaxKind.DefaultClause:
case SyntaxKind.LabelledStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.TryStatement:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.EnumMember:
case SyntaxKind.SourceFile:
forEachChild(node, checkFunctionExpressionBodies);
break;
}
}

function checkBody(node: Block) {
checkBlock(node);
checkFunctionExpressionBodies(node);
}

// Fully type check a source file and collect the relevant diagnostics.
function checkSourceFile(node: SourceFile) {
var links = getNodeLinks(node);
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
emitExtends = false;
potentialThisCollisions.length = 0;
forEach(node.statements, checkSourceElement);
checkBody(node);
if (isExternalModule(node)) {
var symbol = getExportAssignmentSymbol(node.symbol);
if (symbol && symbol.flags & SymbolFlags.Import) {
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/declFileTypeofFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ declare function b1(): typeof b1;
declare function foo(): typeof foo;
declare var foo1: typeof foo;
declare var foo2: typeof foo;
declare var foo3: any;
declare var x: any;
declare var foo3: () => any;
declare var x: () => any;
declare function foo5(x: number): (x: number) => number;
8 changes: 4 additions & 4 deletions tests/baselines/reference/declFileTypeofFunction.types
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ var foo2 = foo;
>foo : () => typeof foo

var foo3 = function () {
>foo3 : any
>foo3 : () => any
>function () { return foo3;} : () => any

return foo3;
>foo3 : any
>foo3 : () => any
}
var x = () => {
>x : any
>x : () => any
>() => { return x;} : () => any

return x;
>x : any
>x : () => any
}

function foo5(x: number) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==== tests/cases/compiler/defaultArgsForwardReferencing.ts (12 errors) ====
==== tests/cases/compiler/defaultArgsForwardReferencing.ts (10 errors) ====
function left(a, b = a, c = b) {
a;
b;
Expand Down Expand Up @@ -37,11 +37,7 @@
}

function defaultArgFunction(a = function () { return b; }, b = 1) { }
~
!!! Initializer of parameter 'a' cannot reference identifier 'b' declared after it.
function defaultArgArrow(a = () => () => b, b = 3) { }
~
!!! Initializer of parameter 'a' cannot reference identifier 'b' declared after it.

class C {
constructor(a = b, b = 1) { }
Expand Down
6 changes: 3 additions & 3 deletions tests/baselines/reference/namedFunctionExpressionCall.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/compiler/namedFunctionExpressionCall.ts ===
var recurser = function foo() {
>recurser : any
>recurser : () => void
>function foo() { // using the local name foo(); // using the globally visible name recurser();} : () => void
>foo : () => void

Expand All @@ -11,8 +11,8 @@ var recurser = function foo() {

// using the globally visible name
recurser();
>recurser() : any
>recurser : any
>recurser() : void
>recurser : () => void

};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts (1 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts (2 errors) ====
return {
~~~~~~
!!! A 'return' statement can only be used within a function body.
Expand All @@ -7,6 +7,8 @@

// 'private' should not be considered a member variable here.
private[key] = value;
~~~~~~~
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is interesting.. why was that missed before?
also the comment seems wrong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously this error wouldn't be reported because the expression in the return statement isn't type checked if the return statement occurs in a disallowed location. It's not worth the complexity to recompute whether we should skip the function expression body check phase, so the check always occurs.

!!! Cannot find name 'private'.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously this error wouldn't be reported because the expression in the return statement isn't type checked if the return statement occurs in a disallowed location. It's not worth the complexity to recompute whether we should skip the function expression body check phase, so the check always occurs.


}

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/recursiveInitializer.types
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ var b4 = (!b4) && b4; // expected boolean here. actually 'any'

// (x:string) => any
var f = (x: string) => f(x);
>f : any
>f : (x: string) => any
>(x: string) => f(x) : (x: string) => any
>x : string
>f(x) : any
>f : any
>f : (x: string) => any
>x : string

6 changes: 3 additions & 3 deletions tests/baselines/reference/underscoreTest1.types
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ $('#underscore_button').bind('click', buttonView.onClick);
>onClick : () => void

var fibonacci = _.memoize(function (n) {
>fibonacci : any
>fibonacci : (n: any) => any
>_.memoize(function (n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);}) : (n: any) => any
>_.memoize : <T extends Function>(func: T, hashFunction?: Function) => T
>_ : Underscore.Static
Expand All @@ -616,11 +616,11 @@ var fibonacci = _.memoize(function (n) {
>n : any
>fibonacci(n - 1) + fibonacci(n - 2) : any
>fibonacci(n - 1) : any
>fibonacci : any
>fibonacci : (n: any) => any
>n - 1 : number
>n : any
>fibonacci(n - 2) : any
>fibonacci : any
>fibonacci : (n: any) => any
>n - 2 : number
>n : any

Expand Down