Issue #749: f64::checked_i32/i64/u8/u32/u64 are specified but not built

Open and answer this issue on GitHub.

ready · opened 2026-10-20 · updated 2026-10-20 · 0 comments

How it came up

While #729 was being built (commit f24f5c1), it turned out that f64 has no checked_<T> conversion for any width. Part I 2.2 and ADR-285 D13 both say it does. The emitter writes T::try_from(x) for every checked_ conversion. Rust has no TryFrom<f64> for integers, and the emitter has no receiver type at that point to pick another route.

Rule (already specified, ADR-285 D13)

x.checked_T() with x: f64 is null where x is NaN or its value rounded toward zero lies outside T’s range. Otherwise it is that rounded value. A fractional part is not a reason for null: a conversion out of a float always rounds toward zero, as the truncating_ names do. Check this against D13’s wording before building, and if D13 says otherwise, follow D13.

To build

  1. Add one runtime helper in nikaia_std (e.g. num::checked_from_f64::<T>), generic over the destination, plus the matching std.contracts entries for f64::checked_i32, checked_i64, checked_u8, checked_u32 and checked_u64.
  2. Make the emitter choose the helper when the receiver is f64, and keep T::try_from for integer receivers.
  3. Tests:
    • 1.5.checked_i32() == 1
    • (-1.0).checked_u8() is null
    • 300.0.checked_u8() is null
    • f64::NAN’s checked_i64() is null
    • 4294967295.0.checked_u32() == 4294967295
    • 1e20.checked_u64() is null
  4. Close the gap left by #729 step 1.

Back to Open Issues