Zig Version
0.16.0 with #35566
Steps to Reproduce, Observed Behavior, and Expected Behavior
Followup to #35561 / #35566 (you must use a recent 0.17.0-dev build or cherry-pick that fix to see the relevant errors here)
test{constgpa=std.testing.allocator;// case 1:// this succeeds, as expectedtrystd.testing.expectEqual(@as(u128,340000000000000000000000000000000005),trystd.zon.parse.fromSlice(u128,gpa,"340000000000000000000000000000000005",null,.{}),);// case 2:// test failure: "expected 340000000000000000000000000000000005, found 340000000000000000000000000000000000"// I would instead expect fromSlice() to return an error.ParseZon or error.WrongTypetrystd.testing.expectEqual(@as(u128,340000000000000000000000000000000005),trystd.zon.parse.fromSlice(u128,gpa,"340000000000000000000000000000000005.0",null,.{}),);// case 3:// crash: "panic: integer part of floating point value out of bounds"// I would instead expect fromSlice() to return an error.ParseZon or error.WrongTypetrystd.testing.expectEqual(@as(u128,340282366920938463463374607431768211455),//intMaxtrystd.zon.parse.fromSlice(u128,gpa,"340282366920938463463374607431768211455.0",null,.{}),);}
The two failures are both due to std.zon parsing floats as f128 internally, and then later converting them to the requested integer type. But the 112-bit mantissa of f128 isn't enough to store these near-maximal u128 values.
I find it a bit odd that zon allows you to parse an exact ".0"-float into an int. It's been allowed since the start:
// Test parsing whole number floats as integers
trystd.testing.expectEqual(@as(i8,-1),tryfromSlice(i8,gpa,"-1.0",null,.{}));
trystd.testing.expectEqual(@as(i8,123),tryfromSlice(i8,gpa,"123.0",null,.{}));
Maybe this should just be disallowed -- parsing "12.0" into a u8 should return an error.WrongType.
These failures could both be solved by introducing some standard way to do intFromFloatExact correctly, a way to ask the compiler or stdlib "Convert this float into an equivalent integer. If you can't do it exactly, then error instead". Maybe as a compiler intrinsic and/or an erroring function, like what we have with @addWithOverflow and std.math.add. That would be nice for more than just zon-parsing. Related: #31602, specifically @castholm's counter-proposal.
### Zig Version
0.16.0 with #35566
### Steps to Reproduce, Observed Behavior, and Expected Behavior
Followup to #35561 / #35566 (you must use a recent 0.17.0-dev build or cherry-pick that fix to see the relevant errors here)
```zig
test {
const gpa = std.testing.allocator;
// case 1:
// this succeeds, as expected
try std.testing.expectEqual(
@as(u128, 340000000000000000000000000000000005),
try std.zon.parse.fromSlice(u128, gpa, "340000000000000000000000000000000005", null, .{}),
);
// case 2:
// test failure: "expected 340000000000000000000000000000000005, found 340000000000000000000000000000000000"
// I would instead expect fromSlice() to return an error.ParseZon or error.WrongType
try std.testing.expectEqual(
@as(u128, 340000000000000000000000000000000005),
try std.zon.parse.fromSlice(u128, gpa, "340000000000000000000000000000000005.0", null, .{}),
);
// case 3:
// crash: "panic: integer part of floating point value out of bounds"
// I would instead expect fromSlice() to return an error.ParseZon or error.WrongType
try std.testing.expectEqual(
@as(u128, 340282366920938463463374607431768211455), //intMax
try std.zon.parse.fromSlice(u128, gpa, "340282366920938463463374607431768211455.0", null, .{}),
);
}
```
The two failures are both due to std.zon parsing floats as `f128` internally, and then later converting them to the requested integer type. But the 112-bit mantissa of `f128` isn't enough to store these near-maximal u128 values.
---
I find it a bit odd that zon allows you to parse an exact ".0"-float into an int. It's been allowed since the start:
https://codeberg.org/ziglang/zig/src/commit/13c6eb0d71b253cc55a667e33dbdd4932f3710f1/lib/std/zon/parse.zig#L2493-L2495
Maybe this should just be disallowed -- parsing "12.0" into a u8 should return an `error.WrongType`.
---
These failures could both be solved by introducing some standard way to do `intFromFloatExact` correctly, a way to ask the compiler or stdlib "Convert this float into an equivalent integer. If you can't do it exactly, then error instead". Maybe as a compiler intrinsic and/or an erroring function, like what we have with `@addWithOverflow` and `std.math.add`. That would be nice for more than just zon-parsing. Related: #31602, specifically @castholm's [counter-proposal](https://codeberg.org/ziglang/zig/issues/31602#issuecomment-11941974).