lib/fmt: render i64::MIN via math.absi64, not in-i64 negate (#67)

i64dec computed the magnitude with `n = -n` inside i64, which wraps at
i64::MIN (-MIN == MIN stays negative), so the `for (n > 0)` loop never
ran and println(i64::MIN) emitted only the bare '-'. The whole print/
println/fprint family was affected at the single boundary value (and
int MIN, since int is 8B). ref/hare/fmt/print.ha:124-129 takes the
magnitude through math::absi64 into a u64; do the same (math.absi64
exists, lib/math/math.ww:12). ww's own printf path was already correct
((-v): u64), so print and printf now agree.

fmttest gains fprinti64min + fprintintmin pinning the boundary.
This commit is contained in:
2026-06-13 10:33:57 +09:00
parent 5cab22ecec
commit 69e31355ce
2 changed files with 49 additions and 8 deletions

View File

@@ -22,6 +22,7 @@
package fmt;
import io;
import math;
import memio;
import os;
import strings;
@@ -38,16 +39,18 @@ let i64dec_buf: [21]u8;
// of strconv.i64tos for the pre-printf-family print path; the
// printf-family path below dispatches through strconv directly.
fn i64dec(v: i64) str = {
let neg: bool = false;
let n: i64 = v;
if (n < 0) { neg = true; n = -n; };
// ref/hare/fmt/print.ha:124-129: magnitude via math::absi64 into u64,
// sign tested separately. `n = -n` on an i64 wraps at i64::MIN
// (-MIN == MIN), so the old loop never ran and only the '-' printed.
let neg: bool = v < 0;
let n: u64 = math.absi64(v);
let tmp: [20]u8;
let i: i32 = 0;
if (n == 0) { tmp[0] = '0'; i = 1; };
for (n > 0) {
let d: i64 = n % 10i64;
tmp[i] = (d + 48i64): u8;
n = n / 10i64;
if (n == 0u64) { tmp[0] = '0'; i = 1; };
for (n > 0u64) {
let d: u64 = n % 10u64;
tmp[i] = (d + 48u64): u8;
n = n / 10u64;
i += 1;
};
let out: i32 = 0;