From 8989f1a782a35181550370b5133a1df84c23d7eb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sat, 29 Nov 2014 16:48:28 -0800 Subject: [PATCH] Add greater typesafety in the expression portion of the syntax system. Note: this change reveals that there is definitely some wonkyness going on with nodes like FunctionLikeDeclaration. --- src/compiler/checker.ts | 75 ++++++++++++---------- src/compiler/emitter.ts | 31 +++++++--- src/compiler/parser.ts | 134 ++++++++++++++++++++++------------------ src/compiler/types.ts | 64 +++++++++++++------ 4 files changed, 183 insertions(+), 121 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0d1ad489c72..457f9ad676d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4514,8 +4514,8 @@ module ts { } break; case SyntaxKind.PrefixUnaryExpression: - if ((expr).operator === SyntaxKind.ExclamationToken) { - return narrowType(type, (expr).operand, !assumeTrue); + if ((expr).operator === SyntaxKind.ExclamationToken) { + return narrowType(type,(expr).operand, !assumeTrue); } break; } @@ -4722,8 +4722,9 @@ module ts { function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type { var func = parameter.parent; if (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) { - if (isContextSensitiveExpression(func)) { - var contextualSignature = getContextualSignature(func); + var funcExpr = parameter.parent; + if (isContextSensitiveExpression(funcExpr)) { + var contextualSignature = getContextualSignature(funcExpr); if (contextualSignature) { var funcHasRestParameters = hasRestParameters(func); @@ -4771,7 +4772,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 = getContextualSignature(func); if (signature) { return getReturnTypeOfSignature(signature); } @@ -5053,7 +5054,9 @@ module ts { } else { Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment); - type = checkExpression(memberDecl.name, contextualMapper); + type = memberDecl.name.kind === SyntaxKind.ComputedPropertyName + ? unknownType + : checkExpression(memberDecl.name, contextualMapper); } var prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name); prop.declarations = member.declarations; @@ -5115,7 +5118,7 @@ module ts { return s.valueDeclaration ? s.valueDeclaration.flags : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; } - function checkClassPropertyAccess(node: PropertyAccessExpression, type: Type, prop: Symbol) { + function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, type: Type, prop: Symbol) { var flags = getDeclarationFlagsFromSymbol(prop); // Public properties are always accessible if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) { @@ -5154,7 +5157,15 @@ module ts { } function checkPropertyAccess(node: PropertyAccessExpression) { - var type = checkExpression(node.left); + return checkPropertyAccessCore(node, node.left, node.right); + } + + function checkQualifiedName(node: QualifiedName) { + return checkPropertyAccessCore(node, node.left, node.right); + } + + function checkPropertyAccessCore(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) { + var type = checkExpression(left); if (type === unknownType) return type; if (type !== anyType) { var apparentType = getApparentType(getWidenedType(type)); @@ -5162,10 +5173,10 @@ module ts { // handle cases when type is Type parameter with invalid constraint return unknownType; } - var prop = getPropertyOfType(apparentType, node.right.text); + var prop = getPropertyOfType(apparentType, right.text); if (!prop) { - if (node.right.text) { - error(node.right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(node.right), typeToString(type)); + if (right.text) { + error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type)); } return unknownType; } @@ -5178,8 +5189,8 @@ module ts { // - In a static member function or static member accessor // where this references the constructor function object of a derived class, // a super property access is permitted and must specify a public static member function of the base class. - if (node.left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) { - error(node.right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) { + error(right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); } else { checkClassPropertyAccess(node, type, prop); @@ -5477,7 +5488,7 @@ module ts { // String literals get string literal types unless we're reporting errors argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors ? getStringLiteralType(arg) - : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); } // Use argument expression as error location when reporting errors @@ -5968,9 +5979,9 @@ module ts { } function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type { - var contextualSignature = getContextualSignature(func); + var contextualSignature = getContextualSignature(func); if (func.body.kind !== SyntaxKind.FunctionBlock) { - var unwidenedType = checkAndMarkExpression(func.body, contextualMapper); + var unwidenedType = checkAndMarkExpression(func.body, contextualMapper); var widenedType = getWidenedType(unwidenedType); if (fullTypeCheck && compilerOptions.noImplicitAny && !contextualSignature && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { @@ -6126,7 +6137,7 @@ module ts { checkSourceElement(node.body); } else { - var exprType = checkExpression(node.body); + var exprType = checkExpression(node.body); if (node.type) { checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, /*headMessage*/ undefined); } @@ -6229,7 +6240,7 @@ module ts { return undefinedType; } - function checkPrefixExpression(node: UnaryExpression): Type { + function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type { var operandType = checkExpression(node.operand); switch (node.operator) { case SyntaxKind.PlusToken: @@ -6252,7 +6263,7 @@ module ts { return unknownType; } - function checkPostfixExpression(node: UnaryExpression): Type { + function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type { var operandType = checkExpression(node.operand); var ok = checkArithmeticOperandType(node.operand, operandType, Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type); if (ok) { @@ -6503,12 +6514,12 @@ module ts { // object, it serves as an indicator that all contained function and arrow expressions should be considered to // have the wildcard function type; this form of type check is used during overload resolution to exclude // contextually typed function and arrow expressions in the initial phase. - function checkExpression(node: Expression, contextualMapper?: TypeMapper): Type { + function checkExpression(node: Expression | QualifiedName, contextualMapper?: TypeMapper): Type { var type = checkExpressionNode(node, contextualMapper); - if (contextualMapper && contextualMapper !== identityMapper) { + if (contextualMapper && contextualMapper !== identityMapper && node.kind !== SyntaxKind.QualifiedName) { var signature = getSingleCallSignature(type); if (signature && signature.typeParameters) { - var contextualType = getContextualType(node); + var contextualType = getContextualType(node); if (contextualType) { var contextualSignature = getSingleCallSignature(contextualType); if (contextualSignature && !contextualSignature.typeParameters) { @@ -6526,7 +6537,7 @@ module ts { var ok = (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).left === node) || (node.parent.kind === SyntaxKind.ElementAccessExpression && (node.parent).expression === node) || - ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node)); + ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node)); if (!ok) { error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment); @@ -6535,7 +6546,7 @@ module ts { return type; } - function checkExpressionNode(node: Expression, contextualMapper: TypeMapper): Type { + function checkExpressionNode(node: Expression | QualifiedName, contextualMapper: TypeMapper): Type { switch (node.kind) { case SyntaxKind.Identifier: return checkIdentifier(node); @@ -6558,7 +6569,7 @@ module ts { case SyntaxKind.RegularExpressionLiteral: return globalRegExpType; case SyntaxKind.QualifiedName: - return checkPropertyAccess(node); + return checkQualifiedName(node); case SyntaxKind.ArrayLiteralExpression: return checkArrayLiteral(node, contextualMapper); case SyntaxKind.ObjectLiteralExpression: @@ -6586,9 +6597,9 @@ module ts { case SyntaxKind.VoidExpression: return checkVoidExpression(node); case SyntaxKind.PrefixUnaryExpression: - return checkPrefixExpression(node); + return checkPrefixUnaryExpression(node); case SyntaxKind.PostfixUnaryExpression: - return checkPostfixExpression(node); + return checkPostfixUnaryExpression(node); case SyntaxKind.BinaryExpression: return checkBinaryExpression(node, contextualMapper); case SyntaxKind.ConditionalExpression: @@ -8097,11 +8108,11 @@ module ts { function evalConstant(e: Node): number { switch (e.kind) { case SyntaxKind.PrefixUnaryExpression: - var value = evalConstant((e).operand); + var value = evalConstant((e).operand); if (value === undefined) { return undefined; } - switch ((e).operator) { + switch ((e).operator) { case SyntaxKind.PlusToken: return value; case SyntaxKind.MinusToken: return -value; case SyntaxKind.TildeToken: return enumIsConst ? ~value : undefined; @@ -8839,7 +8850,7 @@ module ts { else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression) { var symbol = getNodeLinks(entityName).resolvedSymbol; if (!symbol) { - checkPropertyAccess(entityName); + checkQualifiedName(entityName); } return getNodeLinks(entityName).resolvedSymbol; } @@ -8885,7 +8896,7 @@ module ts { case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: - var type = checkExpression(node); + var type = checkExpression(node); return type.symbol; case SyntaxKind.ConstructorKeyword: @@ -8976,7 +8987,7 @@ module ts { function getTypeOfExpression(expr: Expression): Type { if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) { - expr = expr.parent; + expr = expr.parent; } return checkExpression(expr); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a68b12bebd7..380a4bb3c52 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2268,6 +2268,12 @@ module ts { emit(node.right); } + function emitQualifiedName(node: QualifiedName) { + emit(node.left); + write("."); + emit(node.right); + } + function emitIndexedAccess(node: ElementAccessExpression) { if (tryEmitConstantValue(node)) { return; @@ -2374,10 +2380,8 @@ module ts { emit(node.expression); } - function emitUnaryExpression(node: UnaryExpression) { - if (node.kind === SyntaxKind.PrefixUnaryExpression) { - write(tokenToString(node.operator)); - } + function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { + write(tokenToString(node.operator)); // In some cases, we need to emit a space between the operator and the operand. One obvious case // is when the operator is an identifier, like delete or typeof. We also need to do this for plus // and minus expressions in certain cases. Specifically, consider the following two cases (parens @@ -2394,7 +2398,7 @@ module ts { write(" "); } else if (node.kind === SyntaxKind.PrefixUnaryExpression && node.operand.kind === SyntaxKind.PrefixUnaryExpression) { - var operand = node.operand; + var operand = node.operand; if (node.operator === SyntaxKind.PlusToken && (operand.operator === SyntaxKind.PlusToken || operand.operator === SyntaxKind.PlusPlusToken)) { write(" "); } @@ -2403,11 +2407,17 @@ module ts { } } emit(node.operand); - if (node.kind === SyntaxKind.PostfixUnaryExpression) { - write(tokenToString(node.operator)); - } } + function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { + if (node.operator >= SyntaxKind.Identifier) { + write(" "); + } + emit(node.operand); + write(tokenToString(node.operator)); + } + + function emitBinaryExpression(node: BinaryExpression) { emit(node.left); if (node.operator !== SyntaxKind.CommaToken) write(" "); @@ -3494,7 +3504,7 @@ module ts { case SyntaxKind.TemplateSpan: return emitTemplateSpan(node); case SyntaxKind.QualifiedName: - return emitPropertyAccess(node); + return emitQualifiedName(node); case SyntaxKind.ArrayLiteralExpression: return emitArrayLiteral(node); case SyntaxKind.ObjectLiteralExpression: @@ -3530,8 +3540,9 @@ module ts { case SyntaxKind.VoidExpression: return emitVoidExpression(node); case SyntaxKind.PrefixUnaryExpression: + return emitPrefixUnaryExpression(node); case SyntaxKind.PostfixUnaryExpression: - return emitUnaryExpression(node); + return emitPostfixUnaryExpression(node); case SyntaxKind.BinaryExpression: return emitBinaryExpression(node); case SyntaxKind.ConditionalExpression: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 654abac6d57..df6c2488b0f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -285,8 +285,9 @@ module ts { case SyntaxKind.VoidExpression: return child((node).expression); case SyntaxKind.PrefixUnaryExpression: + return child((node).operand); case SyntaxKind.PostfixUnaryExpression: - return child((node).operand); + return child((node).operand); case SyntaxKind.BinaryExpression: return child((node).left) || child((node).right); @@ -1557,8 +1558,8 @@ module ts { return entity; } - function parseAnyTokenNode(): Node { - var node = createNode(token); + function parseAnyTokenNode(): PrimaryExpression { + var node = createNode(token); nextToken(); return finishNode(node); } @@ -1572,7 +1573,7 @@ module ts { return createMissingNode(); } - function parseTemplateExpression() { + function parseTemplateExpression(): TemplateExpression { var template = createNode(SyntaxKind.TemplateExpression); template.head = parseLiteralNode(); @@ -2396,7 +2397,7 @@ module ts { } else { // If not, we're probably better off bailing out and returning a bogus function expression. - return makeFunctionExpression(SyntaxKind.ArrowFunction, pos, /*asteriskToken:*/ undefined, /*name:*/ undefined, sig, createMissingNode()); + return makeFunctionExpression(SyntaxKind.ArrowFunction, pos, /*asteriskToken:*/ undefined, /*name:*/ undefined, sig, createMissingNode()); } } @@ -2510,7 +2511,7 @@ module ts { } function parseArrowExpressionTail(pos: number, sig: ParsedSignature): FunctionExpression { - var body: Node; + var body: Block | Expression; if (token === SyntaxKind.OpenBraceToken) { body = parseFunctionBlock(/*allowYield:*/ false, /* ignoreMissingOpenBrace */ false); @@ -2635,8 +2636,37 @@ module ts { return finishNode(node); } - function parseUnaryExpressionOrHigher(): Expression { - var pos = getNodePos(); + function parsePrefixUnaryExpression() { + var node = createNode(SyntaxKind.PrefixUnaryExpression); + var operator = token; + nextToken(); + node.operator = operator; + node.operand = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseDeleteExpression() { + var node = createNode(SyntaxKind.DeleteExpression); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseTypeOfExpression() { + var node = createNode(SyntaxKind.TypeOfExpression); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseVoidExpression() { + var node = createNode(SyntaxKind.VoidExpression); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseUnaryExpressionOrHigher(): UnaryExpression { switch (token) { case SyntaxKind.PlusToken: case SyntaxKind.MinusToken: @@ -2644,24 +2674,13 @@ module ts { case SyntaxKind.ExclamationToken: case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: - var operator = token; - nextToken(); - return makeUnaryExpression(SyntaxKind.PrefixUnaryExpression, pos, operator, parseUnaryExpressionOrHigher()); + return parsePrefixUnaryExpression(); case SyntaxKind.DeleteKeyword: - var node = createNode(SyntaxKind.DeleteExpression); - nextToken(); - node.expression = parseUnaryExpressionOrHigher(); - return finishNode(node); + return parseDeleteExpression(); case SyntaxKind.TypeOfKeyword: - var node = createNode(SyntaxKind.TypeOfExpression); - nextToken(); - node.expression = parseUnaryExpressionOrHigher(); - return finishNode(node); + return parseTypeOfExpression(); case SyntaxKind.VoidKeyword: - var node = createNode(SyntaxKind.VoidExpression); - nextToken(); - node.expression = parseUnaryExpressionOrHigher(); - return finishNode(node); + return parseVoidExpression(); case SyntaxKind.LessThanToken: return parseTypeAssertion(); default: @@ -2669,20 +2688,22 @@ module ts { } } - function parsePostfixExpressionOrHigher(): Expression { + function parsePostfixExpressionOrHigher(): PostfixExpression { var expression = parseLeftHandSideExpressionOrHigher(); Debug.assert(isLeftHandSideExpression(expression)); if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { - var operator = token; + var node = createNode(SyntaxKind.PostfixUnaryExpression, expression.pos); + node.operand = expression; + node.operator = token; nextToken(); - return makeUnaryExpression(SyntaxKind.PostfixUnaryExpression, expression.pos, operator, expression); + return finishNode(node); } return expression; } - function parseLeftHandSideExpressionOrHigher(): Expression { + function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { // Original Ecma: // LeftHandSideExpression: See 11.2 // NewExpression @@ -2713,7 +2734,7 @@ module ts { // the last two CallExpression productions. Or we have a MemberExpression which either // completes the LeftHandSideExpression, or starts the beginning of the first four // CallExpression productions. - var expression: Expression; + var expression: MemberExpression; if (token === SyntaxKind.SuperKeyword) { expression = parseSuperExpression(); } @@ -2726,7 +2747,7 @@ module ts { return parseCallExpressionRest(expression); } - function parseMemberExpressionOrHigher(): Expression { + function parseMemberExpressionOrHigher(): MemberExpression { // Note: to make our lives simpler, we decompose the the NewExpression productions and // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. // like so: @@ -2778,7 +2799,7 @@ module ts { return parseMemberExpressionRest(expression); } - function parseSuperExpression(): Expression { + function parseSuperExpression(): MemberExpression { var expression = parseAnyTokenNode(); if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.DotToken) { return expression; @@ -2802,14 +2823,7 @@ module ts { return finishNode(node); } - function makeUnaryExpression(kind: SyntaxKind, pos: number, operator: SyntaxKind, operand: Expression): UnaryExpression { - var node = createNode(kind, pos); - node.operator = operator; - node.operand = operand; - return finishNode(node); - } - - function parseMemberExpressionRest(expression: Expression): Expression { + function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression { while (true) { var dotOrBracketStart = scanner.getTokenPos(); if (parseOptional(SyntaxKind.DotToken)) { @@ -2867,7 +2881,7 @@ module ts { } } else { - indexedAccess.argumentExpression = createMissingNode(); + indexedAccess.argumentExpression = createMissingNode(); } indexedAccess.closeBracketToken = parseTokenNode(SyntaxKind.CloseBracketToken); @@ -2885,11 +2899,11 @@ module ts { continue; } - return expression; + return expression; } } - function parseCallExpressionRest(expression: Expression): Expression { + function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression { while (true) { expression = parseMemberExpressionRest(expression); @@ -2950,7 +2964,7 @@ module ts { return parseType(); } - function parsePrimaryExpression(): Expression { + function parsePrimaryExpression(): PrimaryExpression { switch (token) { case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: @@ -2963,11 +2977,11 @@ module ts { case SyntaxKind.NoSubstitutionTemplateLiteral: return parseLiteralNode(); case SyntaxKind.OpenParenToken: - return parseParenExpression(); + return parseParenthesizedExpression(); case SyntaxKind.OpenBracketToken: - return parseArrayLiteral(); + return parseArrayLiteralExpression(); case SyntaxKind.OpenBraceToken: - return parseObjectLiteral(); + return parseObjectLiteralExpression(); case SyntaxKind.FunctionKeyword: return parseFunctionExpression(); case SyntaxKind.NewKeyword: @@ -2987,10 +3001,10 @@ module ts { } } error(Diagnostics.Expression_expected); - return createMissingNode(); + return createMissingNode(); } - function parseParenExpression(): ParenthesizedExpression { + function parseParenthesizedExpression(): ParenthesizedExpression { var node = createNode(SyntaxKind.ParenthesizedExpression); parseExpected(SyntaxKind.OpenParenToken); node.expression = allowInAnd(parseExpression); @@ -3000,7 +3014,7 @@ module ts { function parseAssignmentExpressionOrOmittedExpression(): Expression { return token === SyntaxKind.CommaToken - ? createNode(SyntaxKind.OmittedExpression) + ? createNode(SyntaxKind.OmittedExpression) : parseAssignmentExpressionOrHigher(); } @@ -3012,7 +3026,7 @@ module ts { return allowInAnd(parseAssignmentExpressionOrOmittedExpression); } - function parseArrayLiteral(): ArrayLiteralExpression { + function parseArrayLiteralExpression(): ArrayLiteralExpression { var node = createNode(SyntaxKind.ArrayLiteralExpression); parseExpected(SyntaxKind.OpenBracketToken); if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; @@ -3077,7 +3091,7 @@ module ts { return parsePropertyAssignment(); } - function parseObjectLiteral(): ObjectLiteralExpression { + function parseObjectLiteralExpression(): ObjectLiteralExpression { var node = createNode(SyntaxKind.ObjectLiteralExpression); parseExpected(SyntaxKind.OpenBraceToken); if (scanner.hasPrecedingLineBreak()) { @@ -3109,7 +3123,7 @@ module ts { return isIdentifier() ? parseIdentifier() : undefined; } - function makeFunctionExpression(kind: SyntaxKind, pos: number, asteriskToken: Node, name: Identifier, sig: ParsedSignature, body: Node): FunctionExpression { + function makeFunctionExpression(kind: SyntaxKind, pos: number, asteriskToken: Node, name: Identifier, sig: ParsedSignature, body: Block | Expression): FunctionExpression { var node = createNode(kind, pos); node.asteriskToken = asteriskToken; node.name = name; @@ -4236,17 +4250,17 @@ module ts { case SyntaxKind.FunctionDeclaration: return checkFunctionDeclaration(node); case SyntaxKind.FunctionExpression: return checkFunctionExpression(node); case SyntaxKind.GetAccessor: return checkGetAccessor(node); - case SyntaxKind.ElementAccessExpression: return checkIndexedAccess(node); + case SyntaxKind.ElementAccessExpression: return checkElementAccessExpression(node); case SyntaxKind.IndexSignature: return checkIndexSignature(node); case SyntaxKind.InterfaceDeclaration: return checkInterfaceDeclaration(node); case SyntaxKind.LabeledStatement: return checkLabeledStatement(node); case SyntaxKind.Method: return checkMethod(node); case SyntaxKind.ModuleDeclaration: return checkModuleDeclaration(node); - case SyntaxKind.ObjectLiteralExpression: return checkObjectLiteral(node); + case SyntaxKind.ObjectLiteralExpression: return checkObjectLiteralExpression(node); case SyntaxKind.NumericLiteral: return checkNumericLiteral(node); case SyntaxKind.Parameter: return checkParameter(node); - case SyntaxKind.PostfixUnaryExpression: return checkPostfixOperator(node); - case SyntaxKind.PrefixUnaryExpression: return checkPrefixOperator(node); + case SyntaxKind.PostfixUnaryExpression: return checkPostfixUnaryExpression(node); + case SyntaxKind.PrefixUnaryExpression: return checkPrefixUnaryExpression(node); case SyntaxKind.Property: return checkProperty(node); case SyntaxKind.PropertyAssignment: return checkPropertyAssignment(node); case SyntaxKind.ReturnStatement: return checkReturnStatement(node); @@ -4567,7 +4581,7 @@ module ts { } if (expression.kind === SyntaxKind.PrefixUnaryExpression) { - var unaryExpression = expression; + var unaryExpression = expression; if (unaryExpression.operator === SyntaxKind.PlusToken || unaryExpression.operator === SyntaxKind.MinusToken) { expression = unaryExpression.operand; } @@ -4632,7 +4646,7 @@ module ts { checkAccessor(node); } - function checkIndexedAccess(node: ElementAccessExpression) { + function checkElementAccessExpression(node: ElementAccessExpression) { if (node.argumentExpression.kind === SyntaxKind.Missing) { if (node.parent.kind === SyntaxKind.NewExpression && (node.parent).expression === node) { @@ -4763,7 +4777,7 @@ module ts { } } - function checkObjectLiteral(node: ObjectLiteralExpression): boolean { + function checkObjectLiteralExpression(node: ObjectLiteralExpression): boolean { var seen: Map = {}; var Property = 1; var GetAccessor = 2; @@ -5029,7 +5043,7 @@ module ts { } } - function checkPostfixOperator(node: UnaryExpression) { + function checkPostfixUnaryExpression(node: PostfixUnaryExpression) { // The identifier eval or arguments may not appear as the LeftHandSideExpression of an // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator. @@ -5038,7 +5052,7 @@ module ts { } } - function checkPrefixOperator(node: UnaryExpression) { + function checkPrefixUnaryExpression(node: PrefixUnaryExpression) { if (node.parserContextFlags & ParserContextFlags.StrictMode) { // The identifier eval or arguments may not appear as the LeftHandSideExpression of an // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression diff --git a/src/compiler/types.ts b/src/compiler/types.ts index dfc39b1612d..437009987e4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -315,7 +315,7 @@ module ts { flags: number; } - export interface Identifier extends Node { + export interface Identifier extends PrimaryExpression { text: string; // Text of identifier (with escapes converted to characters) } @@ -436,23 +436,49 @@ module ts { } export interface Expression extends Node { + _expressionBrand: any; contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution } export interface UnaryExpression extends Expression { + _unaryExpressionBrand: any; + } + + export interface PrefixUnaryExpression extends UnaryExpression { operator: SyntaxKind; operand: Expression; } - export interface DeleteExpression extends Expression { + export interface PostfixUnaryExpression extends PostfixExpression { + operand: LeftHandSideExpression; + operator: SyntaxKind; + } + + export interface PostfixExpression extends UnaryExpression { + _postfixExpressionBrand: any; + } + + export interface LeftHandSideExpression extends PostfixExpression { + _leftHandSideExpressionBrand: any; + } + + export interface MemberExpression extends LeftHandSideExpression { + _memberExpressionBrand: any; + } + + export interface PrimaryExpression extends MemberExpression { + _primaryExpressionBrand: any; + } + + export interface DeleteExpression extends UnaryExpression { expression: Expression; } - export interface TypeOfExpression extends Expression { + export interface TypeOfExpression extends UnaryExpression { expression: Expression; } - export interface VoidExpression extends Expression { + export interface VoidExpression extends UnaryExpression { expression: Expression; } @@ -473,7 +499,7 @@ module ts { whenFalse: Expression; } - export interface FunctionExpression extends Expression, FunctionLikeDeclaration { + export interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclaration { name?: Identifier; body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional } @@ -481,11 +507,11 @@ module ts { // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, // or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters. // For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1". - export interface LiteralExpression extends Expression { + export interface LiteralExpression extends PrimaryExpression { text: string; } - export interface TemplateExpression extends Expression { + export interface TemplateExpression extends PrimaryExpression { head: LiteralExpression; templateSpans: NodeArray; } @@ -497,46 +523,46 @@ module ts { literal: LiteralExpression; } - export interface ParenthesizedExpression extends Expression { + export interface ParenthesizedExpression extends PrimaryExpression { expression: Expression; } - export interface ArrayLiteralExpression extends Expression { + export interface ArrayLiteralExpression extends PrimaryExpression { elements: NodeArray; } - export interface ObjectLiteralExpression extends Expression { + export interface ObjectLiteralExpression extends PrimaryExpression { properties: NodeArray; } - export interface PropertyAccessExpression extends Expression { - left: Expression; + export interface PropertyAccessExpression extends MemberExpression { + left: LeftHandSideExpression; right: Identifier; } - export interface ElementAccessExpression extends Expression { - expression: Expression; + export interface ElementAccessExpression extends MemberExpression { + expression: LeftHandSideExpression; openBracketToken: Node; argumentExpression: Expression; closeBracketToken: Node; } - export interface CallExpression extends Expression { + export interface CallExpression extends LeftHandSideExpression { expression: Expression; typeArguments?: NodeArray; arguments: NodeArray; } - export interface NewExpression extends CallExpression { } + export interface NewExpression extends CallExpression, PrimaryExpression { } - export interface TaggedTemplateExpression extends Expression { - tag: Expression; + export interface TaggedTemplateExpression extends MemberExpression { + tag: LeftHandSideExpression; template: LiteralExpression | TemplateExpression; } export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression; - export interface TypeAssertion extends Expression { + export interface TypeAssertion extends UnaryExpression { type: TypeNode; expression: Expression; }