as is written only where it is shown to fit: NK1241, with checked_<T>() / truncating_<T>() (ADR-285 D12)Open and answer this issue on GitHub.
language, compiler, ready · opened 2026-10-08 · updated 2026-10-10 · 0 comments
While deciding f32 (#552), the owner set the rule for f64 as f32:
Asked whether integers keep their run-time abort, the owner answered that the same principle naturally holds for integers.
ADR-285 D12, D13, Part I 2.2, Part III A.2 and C.3. A conversion that can lose a value is written as only where it is shown to fit. That covers a wider integer to a narrower one, signed to unsigned or back, and an f64 to an integer or to an f32.
NK1116 (as today, D29).as is NK1241. The program writes one of two things:
checked_<T>(), a T? that is null where the value does not fit;truncating_<T>(), or rounding_f32(), which is the backend’s conversion.checked_* now also converts out of an f64; NaN fits no integer.A narrowing as is emitted as try_from (or a std helper out of an f64) and aborts at run time where it does not fit. The corpus has 83 as to an integer type: 60 as i64, 12 as u64, 8 as u32 and 3 as i32. How many of them narrow, and how many the prover shows to fit, is what step 1 finds out.
Build the check as a warning. A narrowing as that the prover does not show to fit is NK1241 at warning severity. Its help names checked_<T>() and truncating_<T>(), and rounding_f32() for f32. A proved one emits a plain conversion. Unproved ones keep today’s run-time check while the warning stands.
Tests:
let small = big as i32 with big: i64 a parameter warns NK1241;assert(big >= 0 && big < 1000) the same line does not warn;5000000000 as i32 is NK1116;k as u64 after if k >= 0 does not warn;f as i32 with f: f64 warns.nikaia lower-std give. Each site is one of three cases:
checked_i32() ?? …, or an assert that proves it). Open an issue to strengthen the prover where that is possible, naming the site and the fact it missed.null from checked_<T>(), or say truncating_<T>() where the low digits are meant. The output may change here, because that is the point of the fix. Say which outputs changed, and why, in the commit.truncating_<T>().checked_* out of an f64. Add std.contracts entries (by hand, D36) and their lowering. Tests: 1e20.checked_i32() is null; (0.0 / 0.0).checked_i64() is null; 3.7.checked_i32() is 3.f32’s half (checked_f32, rounding_f32, as f32) is #552. Build its as f32 step on this check.