diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c9809acc781c2..7e43791dc51f2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -47519,6 +47519,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); }, isImportRequiredByAugmentation, + isNameReferencingGlobalValueAtLocation: (name, location) => { + return resolveEntityName(factory.createIdentifier(name), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ undefined, location) === getGlobalSymbol(escapeLeadingUnderscores(name), SymbolFlags.Value, /*diagnostic*/ undefined); + }, }; function isImportRequiredByAugmentation(node: ImportDeclaration) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d407dadc246ae..66963d1d7fe60 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1182,6 +1182,7 @@ export const notImplementedResolver: EmitResolver = { isBindingCapturedByNode: notImplemented, getDeclarationStatementsForSourceFile: notImplemented, isImportRequiredByAugmentation: notImplemented, + isNameReferencingGlobalValueAtLocation: notImplemented, }; /** diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 00eb218342e00..72eb45599912c 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1901,9 +1901,24 @@ export function transformTypeScript(context: TransformationContext) { function transformEnumMemberDeclarationValue(member: EnumMember): Expression { const value = resolver.getConstantValue(member); if (value !== undefined) { - return typeof value === "string" ? factory.createStringLiteral(value) : - value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))) : - factory.createNumericLiteral(value); + if (typeof value === "string") { + return factory.createStringLiteral(value); + } + if (Number.isNaN(value)) { + return resolver.isNameReferencingGlobalValueAtLocation("NaN", member) + ? factory.createIdentifier("NaN") + : factory.createBinaryExpression(factory.createNumericLiteral(0), SyntaxKind.SlashToken, factory.createNumericLiteral(0)); + } + if (!isFinite(value)) { + if (resolver.isNameReferencingGlobalValueAtLocation("Infinity", member)) { + return value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createIdentifier("Infinity")) : factory.createIdentifier("Infinity"); + } + const dividend = value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(1)) : factory.createNumericLiteral(1); + return factory.createBinaryExpression(dividend, SyntaxKind.SlashToken, factory.createNumericLiteral(0)); + } + return value < 0 + ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))) + : factory.createNumericLiteral(value); } else { enableSubstitutionForNonQualifiedEnumMembers(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2096b177c5930..d1a15f152e67a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5634,6 +5634,7 @@ export interface EmitResolver { isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean; getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined; isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; + isNameReferencingGlobalValueAtLocation(name: string, location: Node): boolean; } // dprint-ignore diff --git a/tests/baselines/reference/enumShadowedInfinityNaN2.js b/tests/baselines/reference/enumShadowedInfinityNaN2.js new file mode 100644 index 0000000000000..ec47a6b130c2a --- /dev/null +++ b/tests/baselines/reference/enumShadowedInfinityNaN2.js @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/enums/enumShadowedInfinityNaN2.ts] //// + +//// [enumShadowedInfinityNaN2.ts] +// repro https://github.com/microsoft/TypeScript/issues/55091 + +let Infinity = 3; +let NaN = 5; + +export enum A { + X = 1 / 0, + Y = -1 / 0, + B = 0 / 0, +} + + +//// [enumShadowedInfinityNaN2.js] +"use strict"; +// repro https://github.com/microsoft/TypeScript/issues/55091 +Object.defineProperty(exports, "__esModule", { value: true }); +exports.A = void 0; +var Infinity = 3; +var NaN = 5; +var A; +(function (A) { + A[A["X"] = 1 / 0] = "X"; + A[A["Y"] = -1 / 0] = "Y"; + A[A["B"] = 0 / 0] = "B"; +})(A || (exports.A = A = {})); diff --git a/tests/baselines/reference/enumShadowedInfinityNaN2.symbols b/tests/baselines/reference/enumShadowedInfinityNaN2.symbols new file mode 100644 index 0000000000000..45f0be86a256c --- /dev/null +++ b/tests/baselines/reference/enumShadowedInfinityNaN2.symbols @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/enums/enumShadowedInfinityNaN2.ts] //// + +=== enumShadowedInfinityNaN2.ts === +// repro https://github.com/microsoft/TypeScript/issues/55091 + +let Infinity = 3; +>Infinity : Symbol(Infinity, Decl(enumShadowedInfinityNaN2.ts, 2, 3)) + +let NaN = 5; +>NaN : Symbol(NaN, Decl(enumShadowedInfinityNaN2.ts, 3, 3)) + +export enum A { +>A : Symbol(A, Decl(enumShadowedInfinityNaN2.ts, 3, 12)) + + X = 1 / 0, +>X : Symbol(A.X, Decl(enumShadowedInfinityNaN2.ts, 5, 15)) + + Y = -1 / 0, +>Y : Symbol(A.Y, Decl(enumShadowedInfinityNaN2.ts, 6, 14)) + + B = 0 / 0, +>B : Symbol(A.B, Decl(enumShadowedInfinityNaN2.ts, 7, 15)) +} + diff --git a/tests/baselines/reference/enumShadowedInfinityNaN2.types b/tests/baselines/reference/enumShadowedInfinityNaN2.types new file mode 100644 index 0000000000000..47d3b511610ea --- /dev/null +++ b/tests/baselines/reference/enumShadowedInfinityNaN2.types @@ -0,0 +1,36 @@ +//// [tests/cases/conformance/enums/enumShadowedInfinityNaN2.ts] //// + +=== enumShadowedInfinityNaN2.ts === +// repro https://github.com/microsoft/TypeScript/issues/55091 + +let Infinity = 3; +>Infinity : number +>3 : 3 + +let NaN = 5; +>NaN : number +>5 : 5 + +export enum A { +>A : A + + X = 1 / 0, +>X : A.X +>1 / 0 : number +>1 : 1 +>0 : 0 + + Y = -1 / 0, +>Y : A.Y +>-1 / 0 : number +>-1 : -1 +>1 : 1 +>0 : 0 + + B = 0 / 0, +>B : A.B +>0 / 0 : number +>0 : 0 +>0 : 0 +} + diff --git a/tests/cases/conformance/enums/enumShadowedInfinityNaN2.ts b/tests/cases/conformance/enums/enumShadowedInfinityNaN2.ts new file mode 100644 index 0000000000000..4da67acc7ec29 --- /dev/null +++ b/tests/cases/conformance/enums/enumShadowedInfinityNaN2.ts @@ -0,0 +1,10 @@ +// repro https://github.com/microsoft/TypeScript/issues/55091 + +let Infinity = 3; +let NaN = 5; + +export enum A { + X = 1 / 0, + Y = -1 / 0, + B = 0 / 0, +}