From db2bf0a309b6885294c5c9e7e2470c595b79cfc6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sun, 30 Nov 2014 21:46:39 -0800 Subject: [PATCH] Address issue where we were having to double cast between FunctionLikeDeclaration and Expression types. Provide brands in a few more places. Anywhere where we have a type that extends another, but only adds optional properties, we should consider brands. Stop SignatureDeclarations from being ClassElements. Instead, only IndexSignatureDeclaration is considered to be a ClassElement. --- src/compiler/checker.ts | 24 ++++++++++++++++-------- src/compiler/parser.ts | 12 ++++++------ src/compiler/types.ts | 12 +++++++++--- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1725d2f9b7c..738c684f554 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4727,11 +4727,10 @@ module ts { // Return contextual type of parameter or undefined if no contextual type is available function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type { - var func = parameter.parent; - if (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) { - var funcExpr = parameter.parent; - if (isContextSensitiveExpression(funcExpr)) { - var contextualSignature = getContextualSignature(funcExpr); + if (isFunctionExpressionOrArrowFunction(parameter.parent)) { + var func = parameter.parent; + if (isContextSensitiveExpression(func)) { + var contextualSignature = getContextualSignature(func); if (contextualSignature) { var funcHasRestParameters = hasRestParameters(func); @@ -4779,7 +4778,7 @@ module ts { } // Otherwise, if the containing function is contextually typed by a function type with exactly one call signature // and that call signature is non-generic, return statements are contextually typed by the return type of the signature - var signature = getContextualSignature(func); + var signature = getContextualSignatureForFunctionLikeDeclaration(func); if (signature) { return getReturnTypeOfSignature(signature); } @@ -4951,12 +4950,21 @@ module ts { } } + function isFunctionExpressionOrArrowFunction(node: Node): boolean { + return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction; + } + + function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature { + // Only function expressions and arrow functions are contextually typed. + return isFunctionExpressionOrArrowFunction(node) ? getContextualSignature(node) : undefined; + } + // Return the contextual signature for a given expression node. A contextual type provides a // contextual signature if it has a single call signature and if that call signature is non-generic. // If the contextual type is a union type, get the signature from each type possible and if they are // all identical ignoring their return type, the result is same signature but with return type as // union type of return types from these signatures - function getContextualSignature(node: Expression): Signature { + function getContextualSignature(node: FunctionExpression): Signature { var type = getContextualType(node); if (!type) { return undefined; @@ -5990,7 +5998,7 @@ module ts { } function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type { - var contextualSignature = getContextualSignature(func); + var contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); if (func.body.kind !== SyntaxKind.FunctionBlock) { var unwidenedType = checkAndMarkExpression(func.body, contextualMapper); var widenedType = getWidenedType(unwidenedType); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6ea284b138d..d3860ef7c77 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -445,11 +445,11 @@ module ts { return false; } - export function getContainingFunction(node: Node): SignatureDeclaration { + export function getContainingFunction(node: Node): FunctionLikeDeclaration { while (true) { node = node.parent; if (!node || isAnyFunction(node)) { - return node; + return node; } } } @@ -1936,8 +1936,8 @@ module ts { }); } - function parseIndexSignatureMember(fullStart: number, modifiers: ModifiersArray): SignatureDeclaration { - var node = createNode(SyntaxKind.IndexSignature, fullStart); + function parseIndexSignatureDeclaration(fullStart: number, modifiers: ModifiersArray): IndexSignatureDeclaration { + var node = createNode(SyntaxKind.IndexSignature, fullStart); setModifiers(node, modifiers); node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); node.type = parseTypeAnnotation(); @@ -1994,7 +1994,7 @@ module ts { return parseSignatureMember(SyntaxKind.CallSignature, SyntaxKind.ColonToken); case SyntaxKind.OpenBracketToken: // Indexer or computed property - return isIndexSignature() ? parseIndexSignatureMember(scanner.getStartPos(), /*modifiers:*/ undefined) : parsePropertyOrMethod(); + return isIndexSignature() ? parseIndexSignatureDeclaration(scanner.getStartPos(), /*modifiers:*/ undefined) : parsePropertyOrMethod(); case SyntaxKind.NewKeyword: if (lookAhead(() => nextToken() === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken)) { return parseSignatureMember(SyntaxKind.ConstructSignature, SyntaxKind.ColonToken); @@ -3779,7 +3779,7 @@ module ts { return parseConstructorDeclaration(fullStart, modifiers); } if (isIndexSignature()) { - return parseIndexSignatureMember(fullStart, modifiers); + return parseIndexSignatureDeclaration(fullStart, modifiers); } // It is very important that we check this *after* checking indexers because // the [ token can start an index signature or a computed property name diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e342eec58ec..81b96ed3072 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -354,7 +354,7 @@ module ts { expression?: Expression; } - export interface SignatureDeclaration extends Declaration, ParsedSignature, ClassElement { + export interface SignatureDeclaration extends Declaration, ParsedSignature { } export interface VariableDeclaration extends Declaration { @@ -383,6 +383,8 @@ module ts { * AccessorDeclaration */ export interface FunctionLikeDeclaration extends SignatureDeclaration { + _functionLikeDeclarationBrand: any; + asteriskToken?: Node; body?: Block | Expression; } @@ -396,14 +398,18 @@ module ts { body?: Block; } - export interface ConstructorDeclaration extends Declaration, ParsedSignature, ClassElement { + export interface ConstructorDeclaration extends FunctionLikeDeclaration, ClassElement { body?: Block; } - export interface AccessorDeclaration extends FunctionLikeDeclaration { + export interface AccessorDeclaration extends FunctionLikeDeclaration, ClassElement { body?: Block; } + export interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement { + _indexSignatureDeclarationBrand: any; + } + export interface TypeNode extends Node { } export interface TypeReferenceNode extends TypeNode {