compiler icon indicating copy to clipboard operation
compiler copied to clipboard

Large-ish numbers not parsed correctly in Elm 0.18, Windows x64

Open ebhasker opened this issue 8 years ago • 8 comments

This seems to be a... Parser / code gen problem

SSCCE (with core and html libraries)

import Html exposing (Html, text)
main : Html msg
main = text (toString (2^31) ++ " versus " ++ toString (2147483648))

Compiling using elm-make under Windows 10, x64, gives me the following in the resulting javascript:

var _user$project$Main$main = _elm_lang$virtual_dom$Native_VirtualDom.staticProgram(
	_elm_lang$html$Html$text(
		A2(
			_elm_lang$core$Basics_ops['++'],
			_elm_lang$core$Basics$toString(
				Math.pow(2, 31)),
			A2(
				_elm_lang$core$Basics_ops['++'],
				' versus ',
				_elm_lang$core$Basics$toString(-2147483648)))));

Note the minus sign, specifically. Suspecting a numerical overflow sort of problem.

Embedding this app and opening in any major browser shows the incorrect output:

2147483648 versus -2147483648

Note that this seems specific to the Windows version. Compiling the same example using elm-make under Linux (Ubuntu 16.04, x64 in my case) gives the javascript output:

var _user$project$Main$main = _elm_lang$virtual_dom$Native_VirtualDom.staticProgram(
	_elm_lang$html$Html$text(
		A2(
			_elm_lang$core$Basics_ops['++'],
			_elm_lang$core$Basics$toString(
				Math.pow(2, 31)),
			A2(
				_elm_lang$core$Basics_ops['++'],
				' versus ',
				_elm_lang$core$Basics$toString(2147483648)))));

Which results in the correct output: 2147483648 versus 2147483648

Note: Numbers less than 2^31 seem to not raise the issue. So hopefully this is also a min-SSCCEE (unless you count negative numbers!)

Please let me know if you need more info about my architecture (i.e. if you cannot reproduce this somehow).

ebhasker avatar Oct 13 '17 21:10 ebhasker

Thanks for the issue! Make sure it satisfies this checklist. My human colleagues will appreciate it!

Here is what to expect next, and if anyone wants to comment, keep these things in mind.

process-bot avatar Oct 13 '17 21:10 process-bot

#1246 for more "int literal weirdness", mentioning it here so these can be batched

zwilias avatar Oct 13 '17 22:10 zwilias

Thanks @zwilias - that indeed looks extremely relevant.

ebhasker avatar Oct 14 '17 00:10 ebhasker

Running OSX 10.11.6 and getting the incorrect output.

Ellie link for ref https://ellie-app.com/rjrWfjNdwa1/0

itsgreggreg avatar Oct 23 '17 23:10 itsgreggreg

Ah. Ellie is sort of a separate case (as it involves the elm-compiler compiled to JS through GHCJS), which makes this effect observable on all platforms due to GHCJS only using 32bits for number, independent of the platform is was compiled on.

Nevertheless, it's the same root-cause listed here: https://github.com/elm-lang/elm-compiler/issues/1246#issuecomment-313390964 - Haskell's Int type doesn't guarantee the same range as representable in the integer part of a JS number.

zwilias avatar Oct 23 '17 23:10 zwilias

Running OSX 10.11.6 and getting the incorrect output.

I can't reproduce this on 0.19 on macOS.

> String.fromInt (2^31) ++ " versus " ++ String.fromInt (2147483648)
"2147483648 versus 2147483648" : String

It may still be reproducible on Windows though!

rtfeldman avatar Aug 11 '18 14:08 rtfeldman

still present in 0.19?

dullbananas avatar Mar 09 '21 19:03 dullbananas

It's not present as is, but if you increase to 64-bit integers, the problem comes back.

For example, in elm repl (0.19.1 on Windows):

>elm repl
---- Elm 0.19.1 ----------------------------------------------------------------
Say :help for help and :exit to exit! More at <https://elm-lang.org/0.19.1/repl>
--------------------------------------------------------------------------------
> 9223372036854775807
9223372036854776000 : number
> 9223372036854775808
-9223372036854776000 : number
>

Overflow because we've reached the limit of 64-bit integers.

Underflow gives a syntax error at least, but for a value that should have been representable (-2^63 = -9223372036854775808)?

> -9223372036854775807
-9223372036854776000 : number
> -9223372036854775808
[stdin]:876
var $author$project$Elm_Repl$repl_input_value_ = --9223372036854775808;
                                                   ^^^^^^^^^^^^^^^^^^^

SyntaxError: Invalid left-hand side expression in prefix operation
    at new Script (vm.js:102:7)
    at createScript (vm.js:262:10)
    at Object.runInThisContext (vm.js:310:10)
    at internal/process/execution.js:81:19
    at [stdin]-wrapper:6:22
    at evalScript (internal/process/execution.js:80:60)
    at internal/main/eval_stdin.js:29:5
    at Socket.<anonymous> (internal/process/execution.js:209:5)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)

Another experiment:

> a: Int
| a = -9223372036854775807
|
-9223372036854776000 : Int
> a = -9223372036854775807
-9223372036854776000 : number
> a: Int
| a = -9223372036854775808
|
[stdin]:876
var $author$project$Elm_Repl$a = --9223372036854775808;
                                   ^^^^^^^^^^^^^^^^^^^

SyntaxError: Invalid left-hand side expression in prefix operation
    at new Script (vm.js:102:7)
    at createScript (vm.js:262:10)
    at Object.runInThisContext (vm.js:310:10)
    at internal/process/execution.js:81:19
    at [stdin]-wrapper:6:22
    at evalScript (internal/process/execution.js:80:60)
    at internal/main/eval_stdin.js:29:5
    at Socket.<anonymous> (internal/process/execution.js:209:5)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
>

In a bizarre twist, if you add another digit (and preserve the previous ones), you get weirdness again (cycles back to 0):

> -92233720368547758070
[stdin]:876
var $author$project$Elm_Repl$repl_input_value_ = --10;
                                                   ^^

SyntaxError: Invalid left-hand side expression in prefix operation
    at new Script (vm.js:102:7)
    at createScript (vm.js:262:10)
    at Object.runInThisContext (vm.js:310:10)
    at internal/process/execution.js:81:19
    at [stdin]-wrapper:6:22
    at evalScript (internal/process/execution.js:80:60)
    at internal/main/eval_stdin.js:29:5
    at Socket.<anonymous> (internal/process/execution.js:209:5)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
> -92233720368547758071
[stdin]:876
var $author$project$Elm_Repl$repl_input_value_ = --9;
                                                   ^

SyntaxError: Invalid left-hand side expression in prefix operation
    at new Script (vm.js:102:7)
    at createScript (vm.js:262:10)
    at Object.runInThisContext (vm.js:310:10)
    at internal/process/execution.js:81:19
    at [stdin]-wrapper:6:22
    at evalScript (internal/process/execution.js:80:60)
    at internal/main/eval_stdin.js:29:5
    at Socket.<anonymous> (internal/process/execution.js:209:5)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
> -92233720368547758080
0 : number
> -9223372036854775808092233720368547758070
[stdin]:876
var $author$project$Elm_Repl$repl_input_value_ = --10;
                                                   ^^

SyntaxError: Invalid left-hand side expression in prefix operation
    at new Script (vm.js:102:7)
    at createScript (vm.js:262:10)
    at Object.runInThisContext (vm.js:310:10)
    at internal/process/execution.js:81:19
    at [stdin]-wrapper:6:22
    at evalScript (internal/process/execution.js:80:60)
    at internal/main/eval_stdin.js:29:5
    at Socket.<anonymous> (internal/process/execution.js:209:5)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
> -9223372036854775808092233720368547758080
0 : number
> -92233720368547758080922337203685477580809223372036854775808092233720368547758070
[stdin]:876
var $author$project$Elm_Repl$repl_input_value_ = --10;
                                                   ^^

SyntaxError: Invalid left-hand side expression in prefix operation
    at new Script (vm.js:102:7)
    at createScript (vm.js:262:10)
    at Object.runInThisContext (vm.js:310:10)
    at internal/process/execution.js:81:19
    at [stdin]-wrapper:6:22
    at evalScript (internal/process/execution.js:80:60)
    at internal/main/eval_stdin.js:29:5
    at Socket.<anonymous> (internal/process/execution.js:209:5)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
> -92233720368547758080922337203685477580809223372036854775808092233720368547758080
0 : number

I can keep going, but you get the gist... 😄

The "double negative sign" seems to point to some strange substitution that happens ('-' + '-10' ?)

This seems related to: https://github.com/elm/compiler/issues/1246

I guess the question transforms into, what should Elm do with an integer overflow / underflow?

My vote is for some sort of make error. Or at least a warning that cautions folks about numbers that are too big/small.

ebhasker avatar Sep 04 '21 01:09 ebhasker