Provide unique nodes for void/typeof/delete expressions.

This commit is contained in:
Cyrus Najmabadi
2014-11-29 13:43:30 -08:00
parent e37f4cec36
commit 6a4927cef7
7 changed files with 140 additions and 41 deletions
+37 -15
View File
@@ -4333,7 +4333,10 @@ module ts {
case SyntaxKind.NewExpression:
case SyntaxKind.TypeAssertion:
case SyntaxKind.ParenExpression:
case SyntaxKind.PrefixOperator:
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.PostfixOperator:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.Block:
@@ -4416,12 +4419,12 @@ module ts {
return type;
function narrowTypeByEquality(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
var left = <UnaryExpression>expr.left;
var left = <TypeOfExpression>expr.left;
var right = <LiteralExpression>expr.right;
// Check that we have 'typeof <symbol>' on the left and string literal on the right
if (left.kind !== SyntaxKind.PrefixOperator || left.operator !== SyntaxKind.TypeOfKeyword ||
left.operand.kind !== SyntaxKind.Identifier || right.kind !== SyntaxKind.StringLiteral ||
getResolvedSymbol(<Identifier>left.operand) !== symbol) {
if (left.kind !== SyntaxKind.TypeOfExpression ||
left.expression.kind !== SyntaxKind.Identifier || right.kind !== SyntaxKind.StringLiteral ||
getResolvedSymbol(<Identifier>left.expression) !== symbol) {
return type;
}
var t = right.text;
@@ -4510,7 +4513,7 @@ module ts {
return narrowTypeByInstanceof(type, <BinaryExpression>expr, assumeTrue);
}
break;
case SyntaxKind.PrefixOperator:
case SyntaxKind.PrefixUnaryExpression:
if ((<UnaryExpression>expr).operator === SyntaxKind.ExclamationToken) {
return narrowType(type, (<UnaryExpression>expr).operand, !assumeTrue);
}
@@ -6211,6 +6214,21 @@ module ts {
return true;
}
function checkDeleteExpression(node: DeleteExpression): Type {
var operandType = checkExpression(node.expression);
return booleanType;
}
function checkTypeOfExpression(node: TypeOfExpression): Type {
var operandType = checkExpression(node.expression);
return stringType;
}
function checkVoidExpression(node: VoidExpression): Type {
var operandType = checkExpression(node.expression);
return undefinedType;
}
function checkPrefixExpression(node: UnaryExpression): Type {
var operandType = checkExpression(node.operand);
switch (node.operator) {
@@ -6219,12 +6237,7 @@ module ts {
case SyntaxKind.TildeToken:
return numberType;
case SyntaxKind.ExclamationToken:
case SyntaxKind.DeleteKeyword:
return booleanType;
case SyntaxKind.TypeOfKeyword:
return stringType;
case SyntaxKind.VoidKeyword:
return undefinedType;
case SyntaxKind.PlusPlusToken:
case SyntaxKind.MinusMinusToken:
var ok = checkArithmeticOperandType(node.operand, operandType, Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
@@ -6566,7 +6579,13 @@ module ts {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return checkFunctionExpression(<FunctionExpression>node, contextualMapper);
case SyntaxKind.PrefixOperator:
case SyntaxKind.TypeOfExpression:
return checkTypeOfExpression(<TypeOfExpression>node);
case SyntaxKind.DeleteExpression:
return checkDeleteExpression(<DeleteExpression>node);
case SyntaxKind.VoidExpression:
return checkVoidExpression(<VoidExpression>node);
case SyntaxKind.PrefixUnaryExpression:
return checkPrefixExpression(<UnaryExpression>node);
case SyntaxKind.PostfixOperator:
return checkPostfixExpression(<UnaryExpression>node);
@@ -8077,7 +8096,7 @@ module ts {
function evalConstant(e: Node): number {
switch (e.kind) {
case SyntaxKind.PrefixOperator:
case SyntaxKind.PrefixUnaryExpression:
var value = evalConstant((<UnaryExpression>e).operand);
if (value === undefined) {
return undefined;
@@ -8478,7 +8497,10 @@ module ts {
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.TypeAssertion:
case SyntaxKind.ParenExpression:
case SyntaxKind.PrefixOperator:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixOperator:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
@@ -8705,7 +8727,7 @@ module ts {
case SyntaxKind.BooleanKeyword:
return true;
case SyntaxKind.VoidKeyword:
return node.parent.kind !== SyntaxKind.PrefixOperator;
return node.parent.kind !== SyntaxKind.VoidExpression;
case SyntaxKind.StringLiteral:
// Specialized signatures can have string literals as their parameters' type names
return node.parent.kind === SyntaxKind.Parameter;
+33 -4
View File
@@ -2339,7 +2339,12 @@ module ts {
// (<any>typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString()
// new (<any>A()) should be emitted as new (A()) and not new A()
// (<any>function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} ()
if (operand.kind !== SyntaxKind.PrefixOperator && operand.kind !== SyntaxKind.PostfixOperator && operand.kind !== SyntaxKind.NewExpression &&
if (operand.kind !== SyntaxKind.PrefixUnaryExpression &&
operand.kind !== SyntaxKind.VoidExpression &&
operand.kind !== SyntaxKind.TypeOfExpression &&
operand.kind !== SyntaxKind.DeleteExpression &&
operand.kind !== SyntaxKind.PostfixOperator &&
operand.kind !== SyntaxKind.NewExpression &&
!(operand.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.NewExpression) &&
!(operand.kind === SyntaxKind.FunctionExpression && node.parent.kind === SyntaxKind.CallExpression)) {
emit(operand);
@@ -2351,8 +2356,26 @@ module ts {
write(")");
}
function emitDeleteExpression(node: DeleteExpression) {
write(tokenToString(SyntaxKind.DeleteKeyword));
write(" ");
emit(node.expression);
}
function emitVoidExpression(node: VoidExpression) {
write(tokenToString(SyntaxKind.VoidKeyword));
write(" ");
emit(node.expression);
}
function emitTypeOfExpression(node: TypeOfExpression) {
write(tokenToString(SyntaxKind.TypeOfKeyword));
write(" ");
emit(node.expression);
}
function emitUnaryExpression(node: UnaryExpression) {
if (node.kind === SyntaxKind.PrefixOperator) {
if (node.kind === SyntaxKind.PrefixUnaryExpression) {
write(tokenToString(node.operator));
}
// In some cases, we need to emit a space between the operator and the operand. One obvious case
@@ -2370,7 +2393,7 @@ module ts {
if (node.operator >= SyntaxKind.Identifier) {
write(" ");
}
else if (node.kind === SyntaxKind.PrefixOperator && node.operand.kind === SyntaxKind.PrefixOperator) {
else if (node.kind === SyntaxKind.PrefixUnaryExpression && node.operand.kind === SyntaxKind.PrefixUnaryExpression) {
var operand = <UnaryExpression>node.operand;
if (node.operator === SyntaxKind.PlusToken && (operand.operator === SyntaxKind.PlusToken || operand.operator === SyntaxKind.PlusPlusToken)) {
write(" ");
@@ -3500,7 +3523,13 @@ module ts {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return emitFunctionDeclaration(<FunctionLikeDeclaration>node);
case SyntaxKind.PrefixOperator:
case SyntaxKind.DeleteExpression:
return emitDeleteExpression(<DeleteExpression>node);
case SyntaxKind.TypeOfExpression:
return emitTypeOfExpression(<TypeOfExpression>node);
case SyntaxKind.VoidExpression:
return emitVoidExpression(<VoidExpression>node);
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixOperator:
return emitUnaryExpression(<UnaryExpression>node);
case SyntaxKind.BinaryExpression:
+47 -17
View File
@@ -278,7 +278,13 @@ module ts {
child((<TypeAssertion>node).operand);
case SyntaxKind.ParenExpression:
return child((<ParenExpression>node).expression);
case SyntaxKind.PrefixOperator:
case SyntaxKind.DeleteExpression:
return child((<DeleteExpression>node).expression);
case SyntaxKind.TypeOfExpression:
return child((<TypeOfExpression>node).expression);
case SyntaxKind.VoidExpression:
return child((<VoidExpression>node).expression);
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixOperator:
return child((<UnaryExpression>node).operand);
case SyntaxKind.BinaryExpression:
@@ -518,7 +524,10 @@ module ts {
case SyntaxKind.ParenExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.PrefixOperator:
case SyntaxKind.VoidExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixOperator:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
@@ -1659,7 +1668,7 @@ module ts {
// <T extends "">
//
// We do *not* want to consume the > as we're consuming the expression for "".
node.expression = parseUnaryExpression();
node.expression = parseUnaryExpressionOrHigher();
}
}
@@ -2532,7 +2541,7 @@ module ts {
}
function parseBinaryExpressionOrHigher(precedence: number): Expression {
var leftOperand = parseUnaryExpression();
var leftOperand = parseUnaryExpressionOrHigher();
return parseBinaryExpressionRest(precedence, leftOperand);
}
@@ -2611,21 +2620,33 @@ module ts {
return finishNode(node);
}
function parseUnaryExpression(): Expression {
function parseUnaryExpressionOrHigher(): Expression {
var pos = getNodePos();
switch (token) {
case SyntaxKind.PlusToken:
case SyntaxKind.MinusToken:
case SyntaxKind.TildeToken:
case SyntaxKind.ExclamationToken:
case SyntaxKind.DeleteKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.PlusPlusToken:
case SyntaxKind.MinusMinusToken:
var operator = token;
nextToken();
return makeUnaryExpression(SyntaxKind.PrefixOperator, pos, operator, parseUnaryExpression());
return makeUnaryExpression(SyntaxKind.PrefixUnaryExpression, pos, operator, parseUnaryExpressionOrHigher());
case SyntaxKind.DeleteKeyword:
var node = <DeleteExpression>createNode(SyntaxKind.DeleteExpression);
nextToken();
node.expression = parseUnaryExpressionOrHigher();
return finishNode(node);
case SyntaxKind.TypeOfKeyword:
var node = <TypeOfExpression>createNode(SyntaxKind.TypeOfExpression);
nextToken();
node.expression = parseUnaryExpressionOrHigher();
return finishNode(node);
case SyntaxKind.VoidKeyword:
var node = <VoidExpression>createNode(SyntaxKind.VoidExpression);
nextToken();
node.expression = parseUnaryExpressionOrHigher();
return finishNode(node);
case SyntaxKind.LessThanToken:
return parseTypeAssertion();
}
@@ -2659,7 +2680,7 @@ module ts {
parseExpected(SyntaxKind.LessThanToken);
node.type = parseType();
parseExpected(SyntaxKind.GreaterThanToken);
node.operand = parseUnaryExpression();
node.operand = parseUnaryExpressionOrHigher();
return finishNode(node);
}
@@ -4073,6 +4094,7 @@ module ts {
case SyntaxKind.ClassDeclaration: return checkClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.ComputedPropertyName: return checkComputedPropertyName(<ComputedPropertyName>node);
case SyntaxKind.Constructor: return checkConstructor(<ConstructorDeclaration>node);
case SyntaxKind.DeleteExpression: return checkDeleteExpression(<DeleteExpression> node);
case SyntaxKind.ExportAssignment: return checkExportAssignment(<ExportAssignment>node);
case SyntaxKind.ForInStatement: return checkForInStatement(<ForInStatement>node);
case SyntaxKind.ForStatement: return checkForStatement(<ForStatement>node);
@@ -4089,7 +4111,7 @@ module ts {
case SyntaxKind.NumericLiteral: return checkNumericLiteral(<LiteralExpression>node);
case SyntaxKind.Parameter: return checkParameter(<ParameterDeclaration>node);
case SyntaxKind.PostfixOperator: return checkPostfixOperator(<UnaryExpression>node);
case SyntaxKind.PrefixOperator: return checkPrefixOperator(<UnaryExpression>node);
case SyntaxKind.PrefixUnaryExpression: return checkPrefixOperator(<UnaryExpression>node);
case SyntaxKind.Property: return checkProperty(<PropertyDeclaration>node);
case SyntaxKind.PropertyAssignment: return checkPropertyAssignment(<PropertyDeclaration>node);
case SyntaxKind.ReturnStatement: return checkReturnStatement(<ReturnStatement>node);
@@ -4355,6 +4377,19 @@ module ts {
}
}
function checkDeleteExpression(node: DeleteExpression) {
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
// operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator
if (node.expression.kind === SyntaxKind.Identifier) {
// When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
// UnaryExpression is a direct reference to a variable, function argument, or function name
return grammarErrorOnNode(node.expression, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode);
}
}
}
function checkEnumDeclaration(enumDecl: EnumDeclaration): boolean {
var enumIsConst = (enumDecl.flags & NodeFlags.Const) !== 0;
@@ -4396,7 +4431,7 @@ module ts {
return /^[0-9]+([eE]\+?[0-9]+)?$/.test(literalExpression.text);
}
if (expression.kind === SyntaxKind.PrefixOperator) {
if (expression.kind === SyntaxKind.PrefixUnaryExpression) {
var unaryExpression = <UnaryExpression>expression;
if (unaryExpression.operator === SyntaxKind.PlusToken || unaryExpression.operator === SyntaxKind.MinusToken) {
expression = unaryExpression.operand;
@@ -4872,11 +4907,6 @@ module ts {
if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) && isEvalOrArgumentsIdentifier(node.operand)) {
return reportInvalidUseInStrictMode(<Identifier>node.operand);
}
else if (node.operator === SyntaxKind.DeleteKeyword && node.operand.kind === SyntaxKind.Identifier) {
// When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
// UnaryExpression is a direct reference to a variable, function argument, or function name
return grammarErrorOnNode(node.operand, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode);
}
}
}
+16 -1
View File
@@ -178,7 +178,10 @@ module ts {
ParenExpression,
FunctionExpression,
ArrowFunction,
PrefixOperator,
DeleteExpression,
TypeOfExpression,
VoidExpression,
PrefixUnaryExpression,
PostfixOperator,
BinaryExpression,
ConditionalExpression,
@@ -438,6 +441,18 @@ module ts {
operator: SyntaxKind;
operand: Expression;
}
export interface DeleteExpression extends Expression {
expression: Expression;
}
export interface TypeOfExpression extends Expression {
expression: Expression;
}
export interface VoidExpression extends Expression {
expression: Expression;
}
export interface YieldExpression extends Expression {
asteriskToken?: Node;
+4 -1
View File
@@ -39,7 +39,10 @@ class TypeWriterWalker {
case ts.SyntaxKind.ParenExpression:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.PrefixOperator:
case ts.SyntaxKind.TypeOfExpression:
case ts.SyntaxKind.VoidExpression:
case ts.SyntaxKind.DeleteExpression:
case ts.SyntaxKind.PrefixUnaryExpression:
case ts.SyntaxKind.PostfixOperator:
case ts.SyntaxKind.BinaryExpression:
case ts.SyntaxKind.ConditionalExpression:
+1 -1
View File
@@ -673,7 +673,7 @@ module ts.formatting {
}
static IsVoidOpContext(context: FormattingContext): boolean {
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.PrefixOperator;
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression;
}
}
}
+2 -2
View File
@@ -4574,7 +4574,7 @@ module ts {
var parent = node.parent;
if (parent) {
if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) {
if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixUnaryExpression) {
return true;
}
else if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).left === node) {
@@ -5063,7 +5063,7 @@ module ts {
// the '=' in a variable declaration is special cased here.
if (token.parent.kind === SyntaxKind.BinaryExpression ||
token.parent.kind === SyntaxKind.VariableDeclaration ||
token.parent.kind === SyntaxKind.PrefixOperator ||
token.parent.kind === SyntaxKind.PrefixUnaryExpression ||
token.parent.kind === SyntaxKind.PostfixOperator ||
token.parent.kind === SyntaxKind.ConditionalExpression) {
return ClassificationTypeNames.operator;