-
Notifications
You must be signed in to change notification settings - Fork 39
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
1e100 is considered convertible to int64 and the result is invalid #93
Comments
|
here is more inconsistency: proc foo1(arg: float64): string =
let x = int64(arg)
$x
proc foo2(arg: float64): string {.compileTime.} =
let x = int64(arg)
$x
echo foo1(1e100)
echo foo2(1e100)
echo int64(1e100) output:
|
I'm currently working on replacing the compiler's int128 implementation with a signed and unsigned int128 implementation. I know we want to revisit the design of the compiler overall, but for now I think providing a better implementation will make these casts easier and understandable and also simpler to spec. Once I have finished the implementations, and the existing tests are passing I will add new ones for the float64 to int128. |
@zacharycarter I've written the int128 type and of course I am biased here, but I don't think the root cause of this bug here is the int128 type or its implementation. I've worked a lot on this type, I know how it works, and I've written a lot of integer handling with different sizes in the VM. There is certainly some shared knowledge between this type and the VM type. Reimplementing int128 to a signed int128 type (sign + absolute value) would remove all of it and therefore I don't like the idea. So I would really like to unstand your problems with the int128 type as it is. Yes there are bugs, but they are to my knowledge not because of the int128 type, they are because of a problematic specification of Nim and developers pulling the language in different directions. My suggestion for this fix would be the following:
This means |
Note that this is not guaranteed. Nim does not have float range check so the behavior varies wildly between architectures. We should look into defining runtime checks for float conversions as well. |
@krux02 - thanks for the reply my dude! I can't say I necessarily have a problem with the implementation, I just don't understand parts of it, and since I needed some frame of reference to test my findings against, I thought the best way would be to port some implementation I knew that was correct and that I could test against.
@krux02 - good to know! I can stop wasting my time here then xD
Okay, I see - thanks for the explanation. I don't know anything about the compiler backend really other than it's a compiler and I have uni textbook knowledge of them. I've barely done anything with Nim's, but I'll look into it.
Okay first I will check out what Arne is suggesting regarding |
For those of us peripherally following along, it seems there are two lessons here:
The direction with VM math operations in the compiler/VM, especially floating point need to be agnostic of the compiler host platform. Instead they should work as per some sort of canonical understanding of the target back-end or a single agreed upon understanding. That way when I compile code on some funky CPU, all the compile time evaluation should be identical to some more popular CPU/mArchitecture for the same code and parameters. This especially matters for floating point numbers, very wide types that are rarely natively supported (128bit integers), or targets that treat don't have real int support (JS). That sounds about right? |
It does but I'm still not sure what to do here in order to make any progress. I think I'm in slightly over my head 😅 I might try to find something simpler to work on - lately I haven't had much time to work on anything and I don't want to commit to something I barely understand to begin with. |
Well I can give you a brief overview of how Nim works here. There are three ways to compute an expression in Nim:
I think option 1 and two are pretty much clear. Not in detail, but generally enough for this conversation. Semfold though is a different thing. It is just a compiler pass that does ast substitutions for simple expressions that can be computed at compile time. This type of code execution is usually implemented in compilers (such as C) as an optimization pass, so that (1+5) becomes a literal 6. I think c++ template metaprogramming is based on something like this. But in Nim, semfold is completely redundant to the VM (and the semfold equivalent in the backend compiler). Except from the part where semfold does error generation for out of range values. Currently I don't know what to do or if my suggestion is still a good suggestion. After all, maybe it is good if the convesion of one googol (yes 1e100 has a name) to int64 would raise an error at runtime and VM as well. |
Right now the only defined rules in Nim are:
I think the right thing to do here is to make |
157: use improved range check of 128 for float64 r=alaviss a=krux02 * Add a range check function to test if a float64 is in rage of the `int128` type. * Use that range check function for `semexpr.checkConvertible` * fixes #93 While this fixes the original issue mentioned above, it does not fix or implement the discussions in that issue. They need to be ported to their own issue. Co-authored-by: Arne Döring <arne.doering@gmx.net>
Example
This was extracted from
tcompiletime_range_checks.nim:45
, where the declaration should have produced an error but didn't.Current Output
Expected Output
A compile-time error
Possible Solution
There are two parts to this issue:
First is this conditional:
nimskull/compiler/semexprs.nim
Lines 183 to 186 in f2a9b0c
Since this value won't fit in
int64
, converting becomelow(int64)
, which of course, is a validint64
value (though do note that in C standard this is undefined). I think either we do the comparison infloat
s, orint128
it, which leads to this second portion:nimskull/compiler/semfold.nim
Lines 400 to 401 in f2a9b0c
toInt128(1e100)
produced0
here, which is invalid, and also means we can't useint128
to perform our checks.Tagging @krux02 here, as he is the author of this code. I'm not sure what is the best to do here, though I think we should code in a range check for numbers that won't fit in
int128
(as a fallback in case the check prior fails).Additional Information
The text was updated successfully, but these errors were encountered: