@@ -10559,7 +10559,7 @@ namespace ts {
10559
10559
for (const declaration of symbol.declarations) {
10560
10560
if (declaration.kind === SyntaxKind.EnumDeclaration) {
10561
10561
for (const member of (declaration as EnumDeclaration).members) {
10562
- if (member.initializer && isStringLiteralLike (member.initializer)) {
10562
+ if (member.initializer && isStringConcatExpression (member.initializer)) {
10563
10563
return links.enumKind = EnumKind.Literal;
10564
10564
}
10565
10565
if (!isLiteralEnumMember(member)) {
@@ -40547,8 +40547,8 @@ namespace ts {
40547
40547
const enumKind = getEnumKind(getSymbolOfNode(member.parent));
40548
40548
const isConstEnum = isEnumConst(member.parent);
40549
40549
const initializer = member.initializer!;
40550
- const value = enumKind === EnumKind.Literal && !isLiteralEnumMember(member) ? undefined : evaluate(initializer);
40551
- if (value !== undefined) {
40550
+ const value = enumKind === EnumKind.Literal && !isLiteralEnumMember(member) ? undefined : evaluate(initializer, member );
40551
+ if (value !== undefined && (enumKind !== EnumKind.Numeric || typeof value === "number") ) {
40552
40552
if (isConstEnum && typeof value === "number" && !isFinite(value)) {
40553
40553
error(initializer, isNaN(value) ?
40554
40554
Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN :
@@ -40576,105 +40576,100 @@ namespace ts {
40576
40576
}
40577
40577
}
40578
40578
return value;
40579
+ }
40579
40580
40580
- function evaluate(expr: Expression): string | number | undefined {
40581
- switch (expr.kind) {
40582
- case SyntaxKind.PrefixUnaryExpression:
40583
- const value = evaluate((expr as PrefixUnaryExpression).operand);
40584
- if (typeof value === "number") {
40585
- switch ((expr as PrefixUnaryExpression).operator) {
40586
- case SyntaxKind.PlusToken: return value;
40587
- case SyntaxKind.MinusToken: return -value;
40588
- case SyntaxKind.TildeToken: return ~value;
40589
- }
40590
- }
40591
- break;
40592
- case SyntaxKind.BinaryExpression:
40593
- const left = evaluate((expr as BinaryExpression).left);
40594
- const right = evaluate((expr as BinaryExpression).right);
40595
- if (typeof left === "number" && typeof right === "number") {
40596
- switch ((expr as BinaryExpression).operatorToken.kind) {
40597
- case SyntaxKind.BarToken: return left | right;
40598
- case SyntaxKind.AmpersandToken: return left & right;
40599
- case SyntaxKind.GreaterThanGreaterThanToken: return left >> right;
40600
- case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right;
40601
- case SyntaxKind.LessThanLessThanToken: return left << right;
40602
- case SyntaxKind.CaretToken: return left ^ right;
40603
- case SyntaxKind.AsteriskToken: return left * right;
40604
- case SyntaxKind.SlashToken: return left / right;
40605
- case SyntaxKind.PlusToken: return left + right;
40606
- case SyntaxKind.MinusToken: return left - right;
40607
- case SyntaxKind.PercentToken: return left % right;
40608
- case SyntaxKind.AsteriskAsteriskToken: return left ** right;
40609
- }
40610
- }
40611
- else if (typeof left === "string" && typeof right === "string" && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) {
40612
- return left + right;
40613
- }
40614
- break;
40615
- case SyntaxKind.StringLiteral:
40616
- case SyntaxKind.NoSubstitutionTemplateLiteral:
40617
- return (expr as StringLiteralLike).text;
40618
- case SyntaxKind.NumericLiteral:
40619
- checkGrammarNumericLiteral(expr as NumericLiteral);
40620
- return +(expr as NumericLiteral).text;
40621
- case SyntaxKind.ParenthesizedExpression:
40622
- return evaluate((expr as ParenthesizedExpression).expression);
40623
- case SyntaxKind.Identifier:
40624
- const identifier = expr as Identifier;
40625
- if (isInfinityOrNaNString(identifier.escapedText)) {
40626
- return +(identifier.escapedText);
40581
+ function evaluate(expr: Expression, location: Declaration): string | number | undefined {
40582
+ switch (expr.kind) {
40583
+ case SyntaxKind.PrefixUnaryExpression:
40584
+ const value = evaluate((expr as PrefixUnaryExpression).operand, location);
40585
+ if (typeof value === "number") {
40586
+ switch ((expr as PrefixUnaryExpression).operator) {
40587
+ case SyntaxKind.PlusToken: return value;
40588
+ case SyntaxKind.MinusToken: return -value;
40589
+ case SyntaxKind.TildeToken: return ~value;
40627
40590
}
40628
- return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), identifier.escapedText);
40629
- case SyntaxKind.ElementAccessExpression:
40630
- case SyntaxKind.PropertyAccessExpression:
40631
- if (isConstantMemberAccess(expr)) {
40632
- const type = getTypeOfExpression(expr.expression);
40633
- if (type.symbol && type.symbol.flags & SymbolFlags.Enum) {
40634
- let name: __String;
40635
- if (expr.kind === SyntaxKind.PropertyAccessExpression) {
40636
- name = expr.name.escapedText;
40637
- }
40638
- else {
40639
- name = escapeLeadingUnderscores(cast(expr.argumentExpression, isLiteralExpression).text);
40591
+ }
40592
+ break;
40593
+ case SyntaxKind.BinaryExpression:
40594
+ const left = evaluate((expr as BinaryExpression).left, location);
40595
+ const right = evaluate((expr as BinaryExpression).right, location);
40596
+ if (typeof left === "number" && typeof right === "number") {
40597
+ switch ((expr as BinaryExpression).operatorToken.kind) {
40598
+ case SyntaxKind.BarToken: return left | right;
40599
+ case SyntaxKind.AmpersandToken: return left & right;
40600
+ case SyntaxKind.GreaterThanGreaterThanToken: return left >> right;
40601
+ case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right;
40602
+ case SyntaxKind.LessThanLessThanToken: return left << right;
40603
+ case SyntaxKind.CaretToken: return left ^ right;
40604
+ case SyntaxKind.AsteriskToken: return left * right;
40605
+ case SyntaxKind.SlashToken: return left / right;
40606
+ case SyntaxKind.PlusToken: return left + right;
40607
+ case SyntaxKind.MinusToken: return left - right;
40608
+ case SyntaxKind.PercentToken: return left % right;
40609
+ case SyntaxKind.AsteriskAsteriskToken: return left ** right;
40610
+ }
40611
+ }
40612
+ else if (typeof left === "string" && typeof right === "string" && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) {
40613
+ return left + right;
40614
+ }
40615
+ break;
40616
+ case SyntaxKind.StringLiteral:
40617
+ case SyntaxKind.NoSubstitutionTemplateLiteral:
40618
+ return (expr as StringLiteralLike).text;
40619
+ case SyntaxKind.NumericLiteral:
40620
+ checkGrammarNumericLiteral(expr as NumericLiteral);
40621
+ return +(expr as NumericLiteral).text;
40622
+ case SyntaxKind.ParenthesizedExpression:
40623
+ return evaluate((expr as ParenthesizedExpression).expression, location);
40624
+ case SyntaxKind.Identifier:
40625
+ if (isInfinityOrNaNString((expr as Identifier).escapedText)) {
40626
+ return +((expr as Identifier).escapedText);
40627
+ }
40628
+ // falls through
40629
+ case SyntaxKind.PropertyAccessExpression:
40630
+ if (isEntityNameExpression(expr)) {
40631
+ const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true);
40632
+ if (symbol) {
40633
+ if (symbol.flags & SymbolFlags.EnumMember) {
40634
+ return evaluateEnumMember(expr, symbol, location);
40635
+ }
40636
+ if (isConstVariable(symbol)) {
40637
+ const declaration = symbol.valueDeclaration as VariableDeclaration | undefined;
40638
+ if (declaration && !declaration.type && declaration.initializer && declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location)) {
40639
+ return evaluate(declaration.initializer, declaration);
40640
40640
}
40641
- return evaluateEnumMember(expr, type.symbol, name);
40642
40641
}
40643
40642
}
40644
- break;
40645
- }
40646
- return undefined;
40647
- }
40648
-
40649
- function evaluateEnumMember(expr: Expression, enumSymbol: Symbol, name: __String) {
40650
- const memberSymbol = enumSymbol.exports!.get(name);
40651
- if (memberSymbol) {
40652
- const declaration = memberSymbol.valueDeclaration;
40653
- if (declaration !== member) {
40654
- if (declaration && isBlockScopedNameDeclaredBeforeUse(declaration, member) && isEnumDeclaration(declaration.parent)) {
40655
- return getEnumMemberValue(declaration as EnumMember);
40656
- }
40657
- error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums);
40658
- return 0;
40659
40643
}
40660
- else {
40661
- error(expr, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(memberSymbol));
40644
+ break;
40645
+ case SyntaxKind.ElementAccessExpression:
40646
+ const root = (expr as ElementAccessExpression).expression;
40647
+ if (isEntityNameExpression(root) && isStringLiteralLike((expr as ElementAccessExpression).argumentExpression)) {
40648
+ const rootSymbol = resolveEntityName(root, SymbolFlags.Value, /*ignoreErrors*/ true);
40649
+ if (rootSymbol && rootSymbol.flags & SymbolFlags.Enum) {
40650
+ const name = escapeLeadingUnderscores(((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text);
40651
+ const member = rootSymbol.exports!.get(name);
40652
+ if (member) {
40653
+ return evaluateEnumMember(expr, member, location);
40654
+ }
40655
+ }
40662
40656
}
40663
- }
40664
- return undefined;
40657
+ break;
40665
40658
}
40659
+ return undefined;
40666
40660
}
40667
40661
40668
- function isConstantMemberAccess(node: Expression): node is AccessExpression {
40669
- const type = getTypeOfExpression(node);
40670
- if (type === errorType) {
40671
- return false;
40662
+ function evaluateEnumMember(expr: Expression, symbol: Symbol, location: Declaration) {
40663
+ const declaration = symbol.valueDeclaration;
40664
+ if (!declaration || declaration === location) {
40665
+ error(expr, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(symbol));
40666
+ return undefined;
40672
40667
}
40673
-
40674
- return node.kind === SyntaxKind.Identifier ||
40675
- node.kind === SyntaxKind.PropertyAccessExpression && isConstantMemberAccess((node as PropertyAccessExpression).expression) ||
40676
- node.kind === SyntaxKind.ElementAccessExpression && isConstantMemberAccess((node as ElementAccessExpression).expression) &&
40677
- isStringLiteralLike((node as ElementAccessExpression).argumentExpression );
40668
+ if (!isBlockScopedNameDeclaredBeforeUse(declaration, location)) {
40669
+ error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums);
40670
+ return 0;
40671
+ }
40672
+ return getEnumMemberValue(declaration as EnumMember );
40678
40673
}
40679
40674
40680
40675
function checkEnumDeclaration(node: EnumDeclaration) {
0 commit comments