The native Int
type has some curious limitations.
Because JS only supports floats, implementations of addition and multiplication is currently implemented as (a + b)  0
and (a * b)  0
respectively (and (a  b)  0
for subtraction).
This ‘works fine’ for small numbers, but when the result overflows (or underflows) the 2^31…2^311 range, the result is illdefined (as in: unexpected and difficult to emulate in any nonJS target language).
There is this issue about replacing (a * b)  0
with Math.imul which would turn the operation into proper wrapping multiplication.
At the same time, some other compiler backends define Int
s and the operations on them differently:

Purerl (compiling to Erlang) uses Erlang’s unbounded arbitrarysize integer type for
Int
. (no overflow possible) 
Pscpp (compiling to C++) uses the C++ primitive
int
type (which on all but the most archaic C++ targets is 32bits), and 32bit wrapping addition/multiplication is used. 
Psgo (compiling to go) uses the go primitive
int
type (which is 32bits on 32bit architectures and 64bits on 64bit architectures), and wrapping addition/multiplication is used. 
Purenix (compiling to Nix) uses the Nix
int
type (which is 64 bits) and 64bit wrapping addition/multiplication is used.  (For completion’s sake) Haskell’s
Int
’s exact range is implementationdefined but it is at least 30 bits. (and there are separate Int32 and Int64 types as well). Arithmetic wraps.
This situation can result in code that is not portable between backends, and the resulting problems are of the ‘sneaky’ kind since rather than being caught by type errors the results of arithmetic is slightly off – but only if sufficiently large numbers are used.
People seem to be regularly bitten by this (#2921, #3145).
What can we do to improve this situation? A couple ideas come to mind:

Be more clear about what the range of
Int
should be: 32bits on all targets?
 Fully implementation defined (potentially unbounded)? (Note that this makes code using
Bounded
instance to check whether certain operations can be performed incompilable on unbounded targets)  Implementationdefined but always
Bounded
?

Specify what should happen on overflow/underflow of arithmetic:
 ‘output is implementationdefined’. (AKA document the current situation)
 'output is exactly what
(a * b)  0
in JS does (requiring nontrivial changes to all other compiler backends)  ‘output wraps’ (requiring a change to the JS compiler backend)
 are there more possibilities?