From d94851042516f5842736601999d94bdbb7f74ed2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 16:19:10 -0800 Subject: [PATCH 1/7] Function and constructor types in the syntax tree. --- src/compiler/binder.ts | 30 +++++++++++++++++++++++++----- src/compiler/checker.ts | 28 ++++++++++++++++++++++++++-- src/compiler/parser.ts | 18 ++++++++++-------- src/compiler/types.ts | 4 +++- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index fe3009da3aa..bfdd41f5010 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -93,7 +93,9 @@ module ts { return (node.name).text; } switch (node.kind) { + case SyntaxKind.ConstructorType: case SyntaxKind.Constructor: return "__constructor"; + case SyntaxKind.FunctionType: case SyntaxKind.CallSignature: return "__call"; case SyntaxKind.ConstructSignature: return "__new"; case SyntaxKind.IndexSignature: return "__index"; @@ -114,8 +116,11 @@ module ts { } // Report errors every position with duplicate declaration // Report errors on previous encountered declarations - var message = symbol.flags & SymbolFlags.BlockScopedVariable ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; - forEach(symbol.declarations, (declaration) => { + var message = symbol.flags & SymbolFlags.BlockScopedVariable + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + : Diagnostics.Duplicate_identifier_0; + + forEach(symbol.declarations, declaration => { file.semanticErrors.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration))); }); file.semanticErrors.push(createDiagnosticForNode(node.name, message, getDisplayName(node))); @@ -233,6 +238,8 @@ module ts { declareModuleMember(node, symbolKind, symbolExcludes); break; } + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: @@ -294,6 +301,13 @@ module ts { } } + function bindFunctionOrConstructorType(node: SignatureDeclaration) { + var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature; + var symbol = createSymbol(symbolKind, getDeclarationName(node)); + addDeclarationToSymbol(symbol, node, symbolKind); + bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false); + } + function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) { var symbol = createSymbol(symbolKind, name); addDeclarationToSymbol(symbol, node, symbolKind); @@ -358,12 +372,12 @@ module ts { case SyntaxKind.CallSignature: bindDeclaration(node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false); break; - case SyntaxKind.Method: - bindDeclaration(node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true); - break; case SyntaxKind.ConstructSignature: bindDeclaration(node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true); break; + case SyntaxKind.Method: + bindDeclaration(node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true); + break; case SyntaxKind.IndexSignature: bindDeclaration(node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false); break; @@ -379,6 +393,12 @@ module ts { case SyntaxKind.SetAccessor: bindDeclaration(node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true); break; + + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + bindFunctionOrConstructorType(node); + break; + case SyntaxKind.TypeLiteral: bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false); break; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6224e37ea53..92d474a6202 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2523,6 +2523,8 @@ module ts { for (var i = 0, len = symbol.declarations.length; i < len; i++) { var node = symbol.declarations[i]; switch (node.kind) { + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: case SyntaxKind.FunctionDeclaration: case SyntaxKind.Method: case SyntaxKind.Constructor: @@ -2961,6 +2963,21 @@ module ts { return links.resolvedType; } + function getTypefromFunctionOrConstructorTypeNode(node: SignatureDeclaration): Type { + var links = getNodeLinks(node); + if (!links.resolvedType) { + var symbol = new Symbol(SymbolFlags.TypeLiteral, "__type"); + symbol.members = {}; + symbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = node.symbol; + symbol.declarations = [node.symbol.declarations[0]]; + + node.symbol.parent = symbol; + + links.resolvedType = createObjectType(TypeFlags.Anonymous, symbol); + } + return links.resolvedType; + } + function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type { var links = getNodeLinks(node); if (!links.resolvedType) { @@ -3011,6 +3028,9 @@ module ts { return getTypeFromUnionTypeNode(node); case SyntaxKind.ParenType: return getTypeFromTypeNode((node).type); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return getTypefromFunctionOrConstructorTypeNode(node); case SyntaxKind.TypeLiteral: return getTypeFromTypeLiteralNode(node); // This function assumes that an identifier or qualified name is a type expression @@ -5858,7 +5878,7 @@ module ts { } if (node.kind === SyntaxKind.NewExpression) { var declaration = signature.declaration; - if (declaration && (declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature)) { + if (declaration && (declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature && declaration.kind !== SyntaxKind.ConstructorType)) { // When resolved signature is a call signature (and not a construct signature) the result type is any if (compilerOptions.noImplicitAny) { error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); @@ -8275,6 +8295,8 @@ module ts { return checkParameter(node); case SyntaxKind.Property: return checkPropertyDeclaration(node); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: @@ -9047,7 +9069,9 @@ module ts { function writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { // Get type of the symbol if this is the valid symbol otherwise get type at location var symbol = getSymbolOfNode(location); - var type = symbol && !(symbol.flags & SymbolFlags.TypeLiteral) ? getTypeOfSymbol(symbol) : getTypeFromTypeNode(location); + var type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.CallSignature | SymbolFlags.ConstructSignature)) + ? getTypeOfSymbol(symbol) + : getTypeFromTypeNode(location); getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d43bff7984a..9cb61feeea6 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -205,6 +205,8 @@ module ts { return child((node).name) || child((node).type) || child((node).initializer); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: @@ -1882,16 +1884,16 @@ module ts { return finishNode(node); } - function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode { - var node = createNode(SyntaxKind.TypeLiteral); - var member = createNode(signatureKind); - var sig = parseSignature(signatureKind, SyntaxKind.EqualsGreaterThanToken, /* returnTokenRequired */ true); + function parseFunctionType(typeKind: SyntaxKind): SignatureDeclaration { + var member = createNode(typeKind); + var sig = parseSignature(typeKind === SyntaxKind.FunctionType ? SyntaxKind.CallSignature : SyntaxKind.ConstructSignature, + SyntaxKind.EqualsGreaterThanToken, /* returnTokenRequired */ true); + member.typeParameters = sig.typeParameters; member.parameters = sig.parameters; member.type = sig.type; finishNode(member); - node.members = createNodeArray(member); - return finishNode(node); + return member; } function parseKeywordAndNoDot(): Node { @@ -2011,10 +2013,10 @@ module ts { function parseType(): TypeNode { if (isStartOfFunctionType()) { - return parseFunctionType(SyntaxKind.CallSignature); + return parseFunctionType(SyntaxKind.FunctionType); } if (token === SyntaxKind.NewKeyword) { - return parseFunctionType(SyntaxKind.ConstructSignature); + return parseFunctionType(SyntaxKind.ConstructorType); } return parseUnionType(); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e9293070766..411be56b8b2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -155,6 +155,8 @@ module ts { IndexSignature, // Type TypeReference, + FunctionType, + ConstructorType, TypeQuery, TypeLiteral, ArrayType, @@ -1357,4 +1359,4 @@ module ts { useCaseSensitiveFileNames(): boolean; getNewLine(): string; } -} +} From 3c9eea2df042df6d695c765320a03e5e69359416 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 16:31:40 -0800 Subject: [PATCH 2/7] Update comment. --- src/compiler/checker.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 92d474a6202..c348b10dceb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2966,6 +2966,13 @@ module ts { function getTypefromFunctionOrConstructorTypeNode(node: SignatureDeclaration): Type { var links = getNodeLinks(node); if (!links.resolvedType) { + // For a given function type "<...>(...) => T" we want to generate a type identical + // to: { <...>(...): T } + // + // We do that by making an anonymous type literal node, and then setting the function + // type as its sole member. To the rest of the checker, this type will be + // indistinguishable from an actual type literal you would have gotten had you used + // the long form. var symbol = new Symbol(SymbolFlags.TypeLiteral, "__type"); symbol.members = {}; symbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = node.symbol; From ba2e4bff10fc9d035936f975f3d6ffbcb6f6c737 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 16:39:48 -0800 Subject: [PATCH 3/7] cr feedback. --- src/compiler/binder.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index bfdd41f5010..4eb8c481926 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -94,11 +94,15 @@ module ts { } switch (node.kind) { case SyntaxKind.ConstructorType: - case SyntaxKind.Constructor: return "__constructor"; + case SyntaxKind.Constructor: + return "__constructor"; case SyntaxKind.FunctionType: - case SyntaxKind.CallSignature: return "__call"; - case SyntaxKind.ConstructSignature: return "__new"; - case SyntaxKind.IndexSignature: return "__index"; + case SyntaxKind.CallSignature: + return "__call"; + case SyntaxKind.ConstructSignature: + return "__new"; + case SyntaxKind.IndexSignature: + return "__index"; } } From 9a50f41af81c1fc2da825f75b3a6f321c3798bbe Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 16:42:51 -0800 Subject: [PATCH 4/7] More CR feedback. --- src/compiler/checker.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c348b10dceb..82cbd1a8b08 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2969,13 +2969,15 @@ module ts { // For a given function type "<...>(...) => T" we want to generate a type identical // to: { <...>(...): T } // - // We do that by making an anonymous type literal node, and then setting the function - // type as its sole member. To the rest of the checker, this type will be - // indistinguishable from an actual type literal you would have gotten had you used - // the long form. + // We do that by making an anonymous type literal type, that points to an anonymous + // type literal symbol, and then setting the function symbol as its sole of the type + // literal symbol. To the rest of the checker, this type will be indistinguishable + // from an actual type literal type you would have gotten had you used the long form. var symbol = new Symbol(SymbolFlags.TypeLiteral, "__type"); symbol.members = {}; symbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = node.symbol; + + Debug.assert(node.symbol.declarations.length === 1); symbol.declarations = [node.symbol.declarations[0]]; node.symbol.parent = symbol; @@ -5885,7 +5887,11 @@ module ts { } if (node.kind === SyntaxKind.NewExpression) { var declaration = signature.declaration; - if (declaration && (declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature && declaration.kind !== SyntaxKind.ConstructorType)) { + if (declaration && + declaration.kind !== SyntaxKind.Constructor && + declaration.kind !== SyntaxKind.ConstructSignature && + declaration.kind !== SyntaxKind.ConstructorType) { + // When resolved signature is a call signature (and not a construct signature) the result type is any if (compilerOptions.noImplicitAny) { error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); From 96613737c240fb73255fe19aeeed27f367f81575 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 16:49:23 -0800 Subject: [PATCH 5/7] Type checker symbols must be transient. --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 82cbd1a8b08..8177db9ee14 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2973,7 +2973,7 @@ module ts { // type literal symbol, and then setting the function symbol as its sole of the type // literal symbol. To the rest of the checker, this type will be indistinguishable // from an actual type literal type you would have gotten had you used the long form. - var symbol = new Symbol(SymbolFlags.TypeLiteral, "__type"); + var symbol = new Symbol(SymbolFlags.TypeLiteral | SymbolFlags.Transient, "__type"); symbol.members = {}; symbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = node.symbol; From 7fc05f5017c9497fa75ebd916b9ead39912a25e2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 17:12:32 -0800 Subject: [PATCH 6/7] CR feedback. --- src/compiler/binder.ts | 13 +++++++++++++ src/compiler/checker.ts | 33 ++++----------------------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 4eb8c481926..37ac1dd9ef1 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -306,10 +306,23 @@ module ts { } function bindFunctionOrConstructorType(node: SignatureDeclaration) { + // For a given function type "<...>(...) => T" we want to generate a type identical + // to: { <...>(...): T } + // + // We do that by making an anonymous type literal type, that points to an anonymous + // type literal symbol, and then setting the function symbol as its sole of the type + // literal symbol. To the rest of the system, this type will be indistinguishable + // from an actual type literal type you would have gotten had you used the long form. + var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature; var symbol = createSymbol(symbolKind, getDeclarationName(node)); addDeclarationToSymbol(symbol, node, symbolKind); bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false); + + var typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type"); + addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral); + typeLiteralSymbol.members = {}; + typeLiteralSymbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = symbol } function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8177db9ee14..76ce1eda182 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2962,32 +2962,8 @@ module ts { } return links.resolvedType; } - - function getTypefromFunctionOrConstructorTypeNode(node: SignatureDeclaration): Type { - var links = getNodeLinks(node); - if (!links.resolvedType) { - // For a given function type "<...>(...) => T" we want to generate a type identical - // to: { <...>(...): T } - // - // We do that by making an anonymous type literal type, that points to an anonymous - // type literal symbol, and then setting the function symbol as its sole of the type - // literal symbol. To the rest of the checker, this type will be indistinguishable - // from an actual type literal type you would have gotten had you used the long form. - var symbol = new Symbol(SymbolFlags.TypeLiteral | SymbolFlags.Transient, "__type"); - symbol.members = {}; - symbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = node.symbol; - - Debug.assert(node.symbol.declarations.length === 1); - symbol.declarations = [node.symbol.declarations[0]]; - - node.symbol.parent = symbol; - - links.resolvedType = createObjectType(TypeFlags.Anonymous, symbol); - } - return links.resolvedType; - } - - function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type { + + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type { var links = getNodeLinks(node); if (!links.resolvedType) { // Deferred resolution of members is handled by resolveObjectTypeMembers @@ -3039,9 +3015,8 @@ module ts { return getTypeFromTypeNode((node).type); case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: - return getTypefromFunctionOrConstructorTypeNode(node); case SyntaxKind.TypeLiteral: - return getTypeFromTypeLiteralNode(node); + return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); // This function assumes that an identifier or qualified name is a type expression // Callers should first ensure this by calling isTypeNode case SyntaxKind.Identifier: @@ -6834,7 +6809,7 @@ module ts { function checkTypeLiteral(node: TypeLiteralNode) { forEach(node.members, checkSourceElement); if (fullTypeCheck) { - var type = getTypeFromTypeLiteralNode(node); + var type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); checkIndexConstraints(type); checkTypeForDuplicateIndexSignatures(node); } From ffa48152eb8329202f604cc2d9c3c8e8da5faf08 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 14 Nov 2014 17:15:01 -0800 Subject: [PATCH 7/7] update comment. --- src/compiler/binder.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 37ac1dd9ef1..18fd8c711b8 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -306,13 +306,12 @@ module ts { } function bindFunctionOrConstructorType(node: SignatureDeclaration) { - // For a given function type "<...>(...) => T" we want to generate a type identical - // to: { <...>(...): T } + // For a given function symbol "<...>(...) => T" we want to generate a symbol identical + // to the one we would get for: { <...>(...): T } // - // We do that by making an anonymous type literal type, that points to an anonymous - // type literal symbol, and then setting the function symbol as its sole of the type - // literal symbol. To the rest of the system, this type will be indistinguishable - // from an actual type literal type you would have gotten had you used the long form. + // We do that by making an anonymous type literal symbol, and then setting the function + // symbol as its sole member. To the rest of the system, this symbol will be indistinguishable + // from an actual type literal symbol you would have gotten had you used the long form. var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature; var symbol = createSymbol(symbolKind, getDeclarationName(node));