Skip to content

Conversation

@JoshuaKGoldberg
Copy link
Contributor

Fixes #29863

Is there a better check for a numeric literal being too large than Number(text) >= Math.pow(2, 53) - 1? This performance difference should be negligible given that only literals of length 16 or more will go through Number.

@IllusionMH
Copy link
Contributor

Better way would be using Number.isSafeInteger(), but it is not available in IE11 😭 (funny that this code uses unsafe integer Math.pow(2, 53) itself, but haven't seen cases when this won't work as expected).

Also looks like there are no tests for error messages related to "negative numbers". Are they needed here?

@AnyhowStep
Copy link
Contributor

AnyhowStep commented Sep 3, 2019

@IllusionMH
Copy link
Contributor

IllusionMH commented Sep 3, 2019

@AnyhowStep as I said - not available in IE11 (both Number.isSafeInteger() and related constants)

UPD. Edited this message to propose inline constant, but AnyhowStep clarified this approach first.

@AnyhowStep
Copy link
Contributor

AnyhowStep commented Sep 3, 2019

Just copy-paste those constants into the TS source code. It's one or two lines at most and gets rid of the "unsafe" pow(2, 53)

Not a big deal

@DanielRosenwasser
Copy link
Member

@typescript-bot test this
@typescript-bot user test this
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 3, 2019

Heya @DanielRosenwasser, I've started to run the parallelized community code test suite on this PR at 281e7a4. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 3, 2019

Heya @DanielRosenwasser, I've started to run the extended test suite on this PR at 281e7a4. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 3, 2019

Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at 281e7a4. You can monitor the build here. It should now contribute to this PR's status checks.

if (diagnosticMessage) {
const withMinus = isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.MinusToken;
const literal = (withMinus ? "-" : "") + "0o" + node.text;
return grammarErrorOnNode(withMinus ? node.parent : node, diagnosticMessage, literal);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is feeding in a userless literal parameter`. It's not a problem per se, but it is very weird to do.

// We can quickly bail out in two common cases:
// * Literals with 15 or fewer characters, as they aren't long enough to reach 2^53 - 1
// * Fractional numbers (e.g. 9000000000000000000000000000.000000001) are inherently imprecise anyway
if (text.length <= 15 || text.indexOf(".") !== -1) {
Copy link
Member

@DanielRosenwasser DanielRosenwasser Sep 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't check for other things like scientific notation (1000000000000000000000000000e1), but you can't do a simple indexOf on e because you don't want to allow 0xbeef.

"category": "Error",
"code": 1356
},
"Numeric literals with absolute values equal to 2^53 or greater are too large to be represented accurately as an integer.": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as integers

@typescript-bot
Copy link
Collaborator

Hey @DanielRosenwasser, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/42584/artifacts?artifactName=tgz&fileId=A372393C0D8B45276B7E5306D2299C13901FF09D6ED421C8CD2A7823D89DBE4202&fileName=/typescript-3.7.0-insiders.20190903.tgz"
    }
}

and then running npm install.

@typescript-bot
Copy link
Collaborator

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

return false;
}

return Number(text) >= Math.pow(2, 53) - 1;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, per the user baselines, should allow 9007199254740991 as 2**53. Will update...

Suggested change
return Number(text) >= Math.pow(2, 53) - 1;
return Number(text) >= 2 ** 53;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IE does not have the exponentiation operator, according to mdn

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it gets downleveled

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I forgot TS down levels syntax, but not methods.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Sep 3, 2019

Turns out this breaks more than we thought. For example, it breaks the Azure SDK with the integer 621355968000000000: https://github.com/Azure/azure-sdk-for-js/blob/dcd9a29b083a63fa1c9888aca4a5da6acda425a6/sdk/servicebus/service-bus/src/util/utils.ts#L106

(@bterlson @ramya-rao-a)

The thing that's interesting is that while almost any operation on that number is lossy, I believe that the numeric literal hasn't lost any precision. That's because the mantissa 621355968 can be accurately represented.

@DanielRosenwasser
Copy link
Member

I guess you can shave off the trailing 0s and see if the number fits, but I'm increasingly convinced that this has more value as a lint rule, and that putting it into TypeScript with the intent of only catching a subset of suspicious code would be worse than having it built into ESLint.

@JoshuaKGoldberg
Copy link
Contributor Author

In that case I'll close this PR and add a quickfix to add an n to numeric literal if it's all /\d+/ digits and >= 2 ** 53. Thanks!

@JoshuaKGoldberg
Copy link
Contributor Author

#33300

@JoshuaKGoldberg JoshuaKGoldberg deleted the imprecise-numeric-literal-error branch March 22, 2022 18:29
@microsoft microsoft locked as resolved and limited conversation to collaborators Oct 21, 2025
@typescript-bot
Copy link
Collaborator

The TypeScript team hasn't accepted the linked issue #29863. If you can get it accepted, this PR will have a better chance of being reviewed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue an error when numeric literals can incur precision loss

5 participants