mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Merge pull request #610 from Microsoft/circularFunctionExpressions
Circular function expressions
This commit is contained in:
commit
e157763d6c
@ -4524,27 +4524,28 @@ module ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
checkSignatureDeclaration(node);
|
||||
}
|
||||
}
|
||||
if (fullTypeCheck && !(links.flags & NodeCheckFlags.TypeChecked)) {
|
||||
checkSignatureDeclaration(node);
|
||||
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) {
|
||||
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, undefined, undefined);
|
||||
}
|
||||
}
|
||||
links.flags |= NodeCheckFlags.TypeChecked;
|
||||
}
|
||||
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) {
|
||||
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, undefined, undefined);
|
||||
}
|
||||
checkFunctionExpressionBodies(node.body);
|
||||
}
|
||||
}
|
||||
|
||||
function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean {
|
||||
if (!(type.flags & (TypeFlags.Any | TypeFlags.NumberLike))) {
|
||||
error(operand, diagnostic);
|
||||
@ -6438,9 +6439,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:
|
||||
@ -6487,13 +6489,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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
@ -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) { }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -11,8 +11,8 @@ var recurser = function foo() {
|
||||
|
||||
// using the globally visible name
|
||||
recurser();
|
||||
>recurser() : any
|
||||
>recurser : any
|
||||
>recurser() : void
|
||||
>recurser : () => void
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -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.
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
// 'private' should not be considered a member variable here.
|
||||
private[key] = value;
|
||||
~~~~~~~
|
||||
!!! Cannot find name 'private'.
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user