Skip to content

Disallow negative numbers in create numeric literal (take 2) #56570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8331,7 +8331,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return factory.createStringLiteral(name, !!singleQuote);
}
if (isNumericLiteralName(name) && startsWith(name, "-")) {
return factory.createComputedPropertyName(factory.createNumericLiteral(+name));
return factory.createComputedPropertyName(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(+name))));
}
return createPropertyNameNodeForIdentifierOrLiteral(name, getEmitScriptTarget(compilerOptions), singleQuote, stringNamed, isMethod);
}
Expand Down Expand Up @@ -47998,8 +47998,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (enumResult) return enumResult;
const literalValue = (type as LiteralType).value;
return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) :
typeof literalValue === "number" ? factory.createNumericLiteral(literalValue) :
factory.createStringLiteral(literalValue);
typeof literalValue === "string" ? factory.createStringLiteral(literalValue) :
literalValue < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(literalValue))) :
factory.createNumericLiteral(literalValue);
}

function createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker) {
Expand Down
5 changes: 4 additions & 1 deletion src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
CaseOrDefaultClause,
cast,
CatchClause,
CharacterCodes,
ClassDeclaration,
ClassElement,
ClassExpression,
Expand Down Expand Up @@ -1254,8 +1255,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode

// @api
function createNumericLiteral(value: string | number, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral {
const text = typeof value === "number" ? value + "" : value;
Debug.assert(text.charCodeAt(0) !== CharacterCodes.minus, "Negative numbers should be created in combination with createPrefixUnaryExpression");
const node = createBaseDeclaration<NumericLiteral>(SyntaxKind.NumericLiteral);
node.text = typeof value === "number" ? value + "" : value;
node.text = text;
node.numericLiteralFlags = numericLiteralFlags;
if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) node.transformFlags |= TransformFlags.ContainsES2015;
return node;
Expand Down
9 changes: 8 additions & 1 deletion src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1798,7 +1798,14 @@ export function transformDeclarations(context: TransformationContext) {
if (shouldStripInternal(m)) return;
// Rewrite enum values to their constants, if available
const constValue = resolver.getConstantValue(m);
return preserveJsDoc(factory.updateEnumMember(m, m.name, constValue !== undefined ? typeof constValue === "string" ? factory.createStringLiteral(constValue) : factory.createNumericLiteral(constValue) : undefined), m);
const newInitializer = constValue === undefined
? undefined
: typeof constValue === "string"
? factory.createStringLiteral(constValue)
: constValue < 0
? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(constValue)))
: factory.createNumericLiteral(constValue);
return preserveJsDoc(factory.updateEnumMember(m, m.name, newInitializer), m);
})),
));
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/generators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2524,7 +2524,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF
labelExpressions = [];
}

const expression = factory.createNumericLiteral(-1);
const expression = factory.createNumericLiteral(Number.MAX_SAFE_INTEGER);
if (labelExpressions[label] === undefined) {
labelExpressions[label] = [expression];
}
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1901,7 +1901,9 @@ 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) : factory.createNumericLiteral(value);
return typeof value === "string" ? factory.createStringLiteral(value) :
value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))) :
factory.createNumericLiteral(value);
}
else {
enableSubstitutionForNonQualifiedEnumMembers();
Expand Down
50 changes: 25 additions & 25 deletions tests/cases/compiler/fakeInfinity1.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
// @strict: true
// @declaration: true
// These are not actually the real infinity.
export type PositiveInfinity = 1e999;
export type NegativeInfinity = -1e999;
export type TypeOfInfinity = typeof Infinity;
export type TypeOfNaN = typeof NaN;
type A = 1e999;
type B = 1e9999;
declare let a: A;
declare let b: B;
a = b;
b = a;
a = Infinity;
a = 1e999;
a = 1e9999;
export type Oops = 123456789123456789123456789123456789123456789123456789;
export const oops = 123456789123456789123456789123456789123456789123456789;
// @strict: true
// @declaration: true

// These are not actually the real infinity.
export type PositiveInfinity = 1e999;
export type NegativeInfinity = -1e999;

export type TypeOfInfinity = typeof Infinity;
export type TypeOfNaN = typeof NaN;

type A = 1e999;
type B = 1e9999;

declare let a: A;
declare let b: B;

a = b;
b = a;

a = Infinity;
a = 1e999;
a = 1e9999;

export type Oops = 123456789123456789123456789123456789123456789123456789;
export const oops = 123456789123456789123456789123456789123456789123456789;
36 changes: 18 additions & 18 deletions tests/cases/compiler/fakeInfinity2.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// @strict: true
// @declaration: true
export enum Foo {
A = 1e999,
B = -1e999,
}
namespace X {
type A = 1e999;
type B = 2e999;
export function f(): A {
throw new Error()
}
}
export const m = X.f();
// @strict: true
// @declaration: true

export enum Foo {
A = 1e999,
B = -1e999,
}

namespace X {
type A = 1e999;
type B = 2e999;

export function f(): A {
throw new Error()
}
}

export const m = X.f();
40 changes: 20 additions & 20 deletions tests/cases/compiler/fakeInfinity3.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// @strict: true
// @declaration: true
export enum Foo {
A = 1e999,
B = -1e999,
}
namespace X {
type A = 1e999;
type B = 2e999;
export function f(): A {
throw new Error()
}
}
export const m = X.f();
export const Infinity = "oops";
// @strict: true
// @declaration: true

export enum Foo {
A = 1e999,
B = -1e999,
}

namespace X {
type A = 1e999;
type B = 2e999;

export function f(): A {
throw new Error()
}
}

export const m = X.f();

export const Infinity = "oops";