enum cleanup: apply constant folding to all enum initializers, inline accesses only for const enums

This commit is contained in:
Vladimir Matveev
2015-03-04 08:17:18 -08:00
parent fedc809c3b
commit 8d089afb34
125 changed files with 935 additions and 944 deletions
+32 -20
View File
@@ -9560,7 +9560,7 @@ module ts {
}
var initializer = member.initializer;
if (initializer) {
autoValue = getConstantValueForEnumMemberInitializer(initializer, enumIsConst);
autoValue = getConstantValueForEnumMemberInitializer(initializer);
if (autoValue === undefined) {
if (enumIsConst) {
error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression);
@@ -9570,7 +9570,7 @@ module ts {
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
// Also, we do not need to check this for ambients because there is already
// a syntax error if it is not a constant.
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined);
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined);
}
}
else if (enumIsConst) {
@@ -9595,7 +9595,7 @@ module ts {
nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed;
}
function getConstantValueForEnumMemberInitializer(initializer: Expression, enumIsConst: boolean): number {
function getConstantValueForEnumMemberInitializer(initializer: Expression): number {
return evalConstant(initializer);
function evalConstant(e: Node): number {
@@ -9608,14 +9608,10 @@ module ts {
switch ((<PrefixUnaryExpression>e).operator) {
case SyntaxKind.PlusToken: return value;
case SyntaxKind.MinusToken: return -value;
case SyntaxKind.TildeToken: return enumIsConst ? ~value : undefined;
case SyntaxKind.TildeToken: return ~value;
}
return undefined;
case SyntaxKind.BinaryExpression:
if (!enumIsConst) {
return undefined;
}
var left = evalConstant((<BinaryExpression>e).left);
if (left === undefined) {
return undefined;
@@ -9641,14 +9637,10 @@ module ts {
case SyntaxKind.NumericLiteral:
return +(<LiteralExpression>e).text;
case SyntaxKind.ParenthesizedExpression:
return enumIsConst ? evalConstant((<ParenthesizedExpression>e).expression) : undefined;
return evalConstant((<ParenthesizedExpression>e).expression);
case SyntaxKind.Identifier:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.PropertyAccessExpression:
if (!enumIsConst) {
return undefined;
}
var member = initializer.parent;
var currentType = getTypeOfSymbol(getSymbolOfNode(member.parent));
var enumType: Type;
@@ -9661,19 +9653,37 @@ module ts {
propertyName = (<Identifier>e).text;
}
else {
var expression: Expression;
if (e.kind === SyntaxKind.ElementAccessExpression) {
if ((<ElementAccessExpression>e).argumentExpression === undefined ||
(<ElementAccessExpression>e).argumentExpression.kind !== SyntaxKind.StringLiteral) {
return undefined;
}
var enumType = getTypeOfNode((<ElementAccessExpression>e).expression);
expression = (<ElementAccessExpression>e).expression;
propertyName = (<LiteralExpression>(<ElementAccessExpression>e).argumentExpression).text;
}
else {
var enumType = getTypeOfNode((<PropertyAccessExpression>e).expression);
expression = (<PropertyAccessExpression>e).expression;
propertyName = (<PropertyAccessExpression>e).name.text;
}
if (enumType !== currentType) {
// expression part in ElementAccess\PropertyAccess should be either identifier or dottedName
var current = expression;
while (current) {
if (current.kind === SyntaxKind.Identifier) {
break;
}
else if (current.kind === SyntaxKind.PropertyAccessExpression) {
current = (<ElementAccessExpression>current).expression;
}
else {
return undefined;
}
}
var enumType = checkExpression(expression);
// allow references to constant members of other enums
if (!(enumType.symbol && (enumType.symbol.flags & SymbolFlags.Enum))) {
return undefined;
}
}
@@ -9681,10 +9691,12 @@ module ts {
if (propertyName === undefined) {
return undefined;
}
var property = getPropertyOfObjectType(enumType, propertyName);
if (!property || !(property.flags & SymbolFlags.EnumMember)) {
return undefined;
}
var propertyDecl = property.valueDeclaration;
// self references are illegal
if (member === propertyDecl) {
@@ -9695,6 +9707,7 @@ module ts {
if (!isDefinedBefore(propertyDecl, member)) {
return undefined;
}
return <number>getNodeLinks(propertyDecl).enumMemberValue;
}
}
@@ -10866,10 +10879,9 @@ module ts {
var symbol = getNodeLinks(node).resolvedSymbol;
if (symbol && (symbol.flags & SymbolFlags.EnumMember)) {
var declaration = symbol.valueDeclaration;
var constantValue: number;
if (declaration.kind === SyntaxKind.EnumMember) {
return getEnumMemberValue(<EnumMember>declaration);
// inline property\index accesses only for const enums
if (isConstEnumDeclaration(symbol.valueDeclaration.parent)) {
return getEnumMemberValue(<EnumMember>symbol.valueDeclaration);
}
}
+5 -8
View File
@@ -4612,15 +4612,12 @@ module ts {
}
function writeEnumMemberDeclarationValue(member: EnumMember) {
if (!member.initializer || isConst(member.parent)) {
var value = resolver.getConstantValue(member);
if (value !== undefined) {
write(value.toString());
return;
}
var value = resolver.getConstantValue(member);
if (value !== undefined) {
write(value.toString());
return;
}
if (member.initializer) {
else if (member.initializer) {
emit(member.initializer);
}
else {