Fix several edge cases with negative Int values in bit arrays on JavaScript #3784
+151
−26
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR fixes incorrect bit arrays being generated for negative
Int
values on JavaScript in two scenarios:When the
size
is greater than 48 bits (i.e. it goes beyond JavaScript's safe integer size). This makes<<-1:64>>
give the correct result.When the value is less than the minimum representable integer for the specified size. This makes
<<-80_000:16>>
give the correct result.Also fixed is pattern matching on signed
Int
values in bit arrays when the size is greater than 48 bits and the value being read is negative, e.g.let assert <<-1:64-signed>> = <<255, 255, 255, 255, 255, 255, 255, 255>>
now passes on JavaScript the same as Erlang.The principle now being followed is that, on JavaScript, one should only have to deal with unsafe integer behaviour when an
Int
's value is outside JavaScript's safe range, and that the size/width used when encoding into or pattern matching on a bit array shouldn't matter if theInt
's value lies within the safe range. i.e. 128-bit wide integer segments are now supported in bit array expressions and patterns on JS, just so long as the value of the integer being encoded/matched is within the safe integer range.Hope that makes sense!
I think this is the best we can do without changing
Int
to be aBigInt
on JavaScript, which is an interesting idea that would better match Erlang, but AFAICT is a non-starter from an FFI backwards compatibility perspective.Note that
BigInt
now appears in the JS prelude. An effort is made to avoid it where possible as it's slower, though this does come at the cost of duplicating most of the body ofbyteArrayToInt()
. IfBigInt
was always used the code would be simpler, but presumably slower in cases where it wasn't required (I haven't done any performance measurements).