diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 097d0c76c08..f4504e67646 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2831,6 +2831,8 @@ module ts { return getTypeFromTupleTypeNode(node); case SyntaxKind.UnionType: return getTypeFromUnionTypeNode(node); + case SyntaxKind.ParenType: + return getTypeFromTypeNode((node).type); case SyntaxKind.TypeLiteral: return getTypeFromTypeLiteralNode(node); // This function assumes that an identifier or qualified name is a type expression @@ -7480,6 +7482,8 @@ module ts { return checkTupleType(node); case SyntaxKind.UnionType: return checkUnionType(node); + case SyntaxKind.ParenType: + return checkSourceElement((node).type); case SyntaxKind.FunctionDeclaration: return checkFunctionDeclaration(node); case SyntaxKind.Block: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b7582b9ed06..ab27d5f289a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -227,6 +227,8 @@ module ts { return children((node).elementTypes); case SyntaxKind.UnionType: return children((node).types); + case SyntaxKind.ParenType: + return child((node).type); case SyntaxKind.ArrayLiteral: return children((node).elements); case SyntaxKind.ObjectLiteral: @@ -1660,6 +1662,14 @@ module ts { return finishNode(node); } + function parseParenType(): ParenTypeNode { + var node = createNode(SyntaxKind.ParenType); + parseExpected(SyntaxKind.OpenParenToken); + node.type = parseType(); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode { var node = createNode(SyntaxKind.TypeLiteral); var member = createNode(signatureKind); @@ -1693,10 +1703,7 @@ module ts { case SyntaxKind.OpenBracketToken: return parseTupleType(); case SyntaxKind.OpenParenToken: - case SyntaxKind.LessThanToken: - return parseFunctionType(SyntaxKind.CallSignature); - case SyntaxKind.NewKeyword: - return parseFunctionType(SyntaxKind.ConstructSignature); + return parseParenType(); default: if (isIdentifier()) { return parseTypeReference(); @@ -1720,18 +1727,18 @@ module ts { case SyntaxKind.NewKeyword: return true; case SyntaxKind.OpenParenToken: - // Only consider an ( as the start of a type if we have () or (id - // We don't want to consider things like (1) as a function type. + // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, + // or something that starts a type. We don't want to consider things like '(1)' a type. return lookAhead(() => { nextToken(); - return token === SyntaxKind.CloseParenToken || isParameter(); + return token === SyntaxKind.CloseParenToken || isParameter() || isType(); }); default: return isIdentifier(); } } - function parseNonUnionType(): TypeNode { + function parsePrimaryType(): TypeNode { var type = parseNonArrayType(); while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) { parseExpected(SyntaxKind.CloseBracketToken); @@ -1742,13 +1749,13 @@ module ts { return type; } - function parseType(): TypeNode { - var type = parseNonUnionType(); + function parseUnionType(): TypeNode { + var type = parsePrimaryType(); if (token === SyntaxKind.BarToken) { var types = >[type]; types.pos = type.pos; while (parseOptional(SyntaxKind.BarToken)) { - types.push(parseNonUnionType()); + types.push(parsePrimaryType()); } types.end = getNodeEnd(); var node = createNode(SyntaxKind.UnionType, type.pos); @@ -1758,6 +1765,48 @@ module ts { return type; } + function isFunctionType(): boolean { + return token === SyntaxKind.LessThanToken || token === SyntaxKind.OpenParenToken && lookAhead(() => { + nextToken(); + if (token === SyntaxKind.CloseParenToken || token === SyntaxKind.DotDotDotToken) { + // ( ) + // ( ... + return true; + } + if (isIdentifier() || isModifier(token)) { + nextToken(); + if (token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || + token === SyntaxKind.QuestionToken || token === SyntaxKind.EqualsToken || + isIdentifier() || isModifier(token)) { + // ( id : + // ( id , + // ( id ? + // ( id = + // ( modifier id + return true; + } + if (token === SyntaxKind.CloseParenToken) { + nextToken(); + if (token === SyntaxKind.EqualsGreaterThanToken) { + // ( id ) => + return true; + } + } + } + return false; + }); + } + + function parseType(): TypeNode { + if (isFunctionType()) { + return parseFunctionType(SyntaxKind.CallSignature); + } + if (token === SyntaxKind.NewKeyword) { + return parseFunctionType(SyntaxKind.ConstructSignature); + } + return parseUnionType(); + } + function parseTypeAnnotation(): TypeNode { return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d062da142d7..f8dd211dad2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -155,6 +155,7 @@ module ts { ArrayType, TupleType, UnionType, + ParenType, // Expression ArrayLiteral, ObjectLiteral, @@ -225,7 +226,7 @@ module ts { FirstFutureReservedWord = ImplementsKeyword, LastFutureReservedWord = YieldKeyword, FirstTypeNode = TypeReference, - LastTypeNode = UnionType, + LastTypeNode = ParenType, FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken, FirstToken = EndOfFileToken, @@ -342,6 +343,10 @@ module ts { types: NodeArray; } + export interface ParenTypeNode extends TypeNode { + type: TypeNode; + } + export interface StringLiteralTypeNode extends TypeNode { text: string; }