lib: retire os.assert/abort shims — assert/abort are builtins (#58 respell)

The flat checker scope makes ANY decl named assert/abort anywhere in
the combined unit disable the builtin unit-wide (the #45 shadow shape:
scope_lookup_prefer's cross-module fallback finds it). lib carried
three colliding @symbol("rt_abort") shims (os, time, strconv/stof)
plus the os.assert wrapper, so a bare assert(cond) in ANY program
importing os mis-bound os.assert and failed arity — a hard blocker for
regex fold-5 (regex.ha:660/670 bring builtin-assert mass). Ruled
respell-now per the recurrence test (#45 -> #58).

Delete the shims and the os.assert wrapper; every bare abort(msg)
caller (regex, strings, utf8, hash, getopt, encoding/*, time, stof)
now lands on the builtin, and the ~40 os.assert(c, m) sites respell to
the builtin assert(c, m) — restoring the exact Hare spelling the lib
ports diverged from (e.g. ref/hare/bytes/tokenize.ha:23). os.assert
had no Hare counterpart (Hare's assert is a language builtin); rule-9
wrapper removed. temp/dirs/bufio already use the non-colliding rtabort
spelling and keep it.

Now-dead 'import os;' lines kept (pre-existing precedent:
lib/strconv/strconv.ww carries one); a tree-wide dead-import sweep is
a separate concern. regex.ww's if+abort workarounds citing #58 stay
for the fold-5 owner to fold back into assert.

combined.ww regenerated for all five selfhost tools + the smoke
fixture via make.
This commit is contained in:
2026-06-04 22:08:07 +09:00
parent e091dfbdbe
commit 3daf134395
18 changed files with 199 additions and 263 deletions

View File

@@ -22,7 +22,7 @@
// (when no continue exists in the loop).
// - Hare `fn foo() T = if (cond) {...} else expr;` expression body
// → ww requires a `{}` block body throughout.
// - Hare bare `assert(cond)` builtin → `os.assert(cond, msg)`;
// - Hare bare `assert(cond)` builtin → `assert(cond, msg)`;
// wwstage cgen has no `assert` intercept (deferred fold).
// - In-file instances of the above hoist pattern: `i_sz` (line 93)
// hoists a per-iteration size cast out of a for-loop comparison
@@ -110,7 +110,7 @@ fn leftshift(d: *decimal, k: u32) void = {
let SZ_BOUND: size = (len(d.digits): size);
let kU64: u64 = (k: u64);
let MAXSHIFT_U32: u32 = (maxshift: u32);
os.assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
if (d.nd == (0u64: size)) { return; };
let nn: u32 = leftshift_newdigits(d, k);
let r: int = (d.nd: int) - 1;

View File

@@ -42,7 +42,7 @@
// (stof.ww hex_to_bits precedent).
// - `&&=` → `x = x && y`. `ibool=if(b)1 else 0` expr-body → block.
// comma `let a=…, b=…` → split. `if/else` expr-yield → pre-bound
// local + block. `assert()` → `os.assert(cond,msg)`.
// local + block. `assert()` → `assert(cond,msg)`.
// - 2D row-bind `mul=TBL[base]` → direct double-index `TBL[base][0/1]`
// (#155 / #156, stof.ww eisel_lemire precedent).
// - ibool's u8 result + the u8 BITCOUNT defs cast explicitly to u32/u64
@@ -62,7 +62,7 @@ import os;
// (u128mul + the r128 struct live in stof.ww, fold-4's first consumer;
// reused in-package here.)
fn u128rshift(lo: u64, hi: u64, s: u32) u64 = {
os.assert(s <= 64u32, "strconv.u128rshift: s > 64");
assert(s <= 64u32, "strconv.u128rshift: s > 64");
return (hi << (64u64 - (s: u64))) | (lo >> (s: u64));
};
@@ -73,7 +73,7 @@ fn pow5fac(v: u64) u32 = {
let n_div_5: u64 = 3689348814741910323u64;
let count: u32 = 0u32;
for (true) {
os.assert(value != 0u64, "strconv.pow5fac: value == 0");
assert(value != 0u64, "strconv.pow5fac: value == 0");
value *= m_inv_5;
if (value > n_div_5) { break; };
count += 1u32;
@@ -92,8 +92,8 @@ fn pow5multiple(v: u64, p: u32) bool = { return pow5fac(v) >= p; };
// ref/hare/strconv/ftos_ryu.ha:69.
fn pow2multiple(v: u64, p: u32) bool = {
os.assert(v > 0u64, "strconv.pow2multiple: v == 0");
os.assert(p < 64u32, "strconv.pow2multiple: p >= 64");
assert(v > 0u64, "strconv.pow2multiple: v == 0");
assert(p < 64u32, "strconv.pow2multiple: p >= 64");
return (v & ((1u64 << (p: u64)) - 1u64)) == 0u64;
};
@@ -136,7 +136,7 @@ fn mulshiftall64(m: u64, mul0: u64, mul1: u64, j: i32, mm_shift: u32) ryuv = {
// ref/hare/strconv/ftos_ryu.ha:140.
fn log2pow5(e: u32) u32 = {
os.assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
return (e * 1217359u32) >> 19u32;
};
@@ -146,13 +146,13 @@ fn pow5bits(e: u32) u32 = { return ceil_log2pow5(e); };
// ref/hare/strconv/ftos_ryu.ha:149.
fn log10pow2(e: u32) u32 = {
os.assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
return (e * 78913u32) >> 18u32;
};
// ref/hare/strconv/ftos_ryu.ha:154.
fn log10pow5(e: u32) u32 = {
os.assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
return (e * 732923u32) >> 20u32;
};
@@ -343,15 +343,15 @@ fn f64todecf64(mantissa: u64, exponent: u32) decf64 = {
// u64 siblings at 32-bit width; they reuse the SHARED f64computeinvpow5/
// f64computepow5 (and thus the f64 SPLIT2 tables) per ftos_ryu.ha — there
// is no separate f32 table. Same scalar-PARAM-mutation → copy-to-local,
// comma-split, assert → os.assert, expr-yield → block divergences as the
// f64 path above. ====
// comma-split, expr-yield → block divergences as the f64 path
// above. ====
// ref/hare/strconv/ftos_ryu.ha:52. Largest p with 5^p | value (32-bit).
fn pow5fac32(v: u32) u32 = {
let value: u32 = v;
let count: u32 = 0u32;
for (true) {
os.assert(value != 0u32, "strconv.pow5fac32: value == 0");
assert(value != 0u32, "strconv.pow5fac32: value == 0");
let q: u32 = value / 5u32;
let r: u32 = value % 5u32;
if (r != 0u32) { break; };
@@ -366,8 +366,8 @@ fn pow5multiple32(v: u32, p: u32) bool = { return pow5fac32(v) >= p; };
// ref/hare/strconv/ftos_ryu.ha:75.
fn pow2multiple32(v: u32, p: u32) bool = {
os.assert(v > 0u32, "strconv.pow2multiple32: v == 0");
os.assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
assert(v > 0u32, "strconv.pow2multiple32: v == 0");
assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
return (v & ((1u32 << p) - 1u32)) == 0u32;
};
@@ -377,14 +377,14 @@ fn pow2multiple32(v: u32, p: u32) bool = {
// (lib/types/types.ww — no `export`), so Hare's `types::U32_MAX` can't be
// referenced cross-package.
fn mulshift32(m: u32, a: u64, s: u32) u32 = {
os.assert(s > 32u32, "strconv.mulshift32: s <= 32");
assert(s > 32u32, "strconv.mulshift32: s <= 32");
let a_lo: u64 = (a: u32): u64;
let a_hi: u64 = a >> 32u64;
let b0: u64 = (m: u64) * a_lo;
let b1: u64 = (m: u64) * a_hi;
let sum: u64 = (b0 >> 32u64) + b1;
let ss: u64 = sum >> ((s: u64) - 32u64);
os.assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
return ss: u32;
};
@@ -533,7 +533,7 @@ fn f32todecf32(mantissa: u32, exponent: u32) decf32 = {
// ref/hare/strconv/ftos.ha:49. Decimal digit-count of n (n <= 1e17).
fn declen(n: u64) uint = {
os.assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
if (n >= 100000000000000000u64) { return (18u32: uint); };
if (n >= 10000000000000000u64) { return (17u32: uint); };
if (n >= 1000000000000000u64) { return (16u32: uint); };
@@ -621,7 +621,7 @@ fn encode_f_dec(d: *decimal, buf: []u8, out: i32) i32 = {
// logic only): no precision zeros, lowercase 'e', no '+'/two-digit pad.
fn encode_e_dec(d: *decimal, buf: []u8, out: i32) i32 = {
let o: i32 = out;
os.assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
buf[o] = (d.digits[0] + 48u8): u8;
o += 1i32;
if ((d.nd: i32) > 1i32) {

View File

@@ -97,8 +97,6 @@ fn todig(c: u8) u8 = {
return 0u8; // unreachable; rt_abort is void-typed (path-cov)
};
@symbol("rt_abort") fn abort(msg: str) void;
// ref/hare/strconv/stof.ha:25.
type fast_parsed_float = struct {
mantissa: u64,
@@ -280,7 +278,7 @@ fn decimal_parse(d: *decimal, s: str) (void | invalid) = {
// ref/hare/strconv/stof.ha:173. Count of leading zero bits in n>0.
fn leading_zeroes(n: u64) uint = {
os.assert(n > 0u64, "strconv.leading_zeroes: n == 0");
assert(n > 0u64, "strconv.leading_zeroes: n == 0");
let b: u64 = 0u64;
if ((n & 0xFFFFFFFF00000000u64) > 0u64) {
n >>= 32u64;
@@ -599,7 +597,7 @@ export fn stof64(s: str, b: base) (f64 | invalid | overflow) = {
} else if (bb == base.HEX_LOWER) {
bb = base.HEX;
};
os.assert(bb == base.DEC || bb == base.HEX,
assert(bb == base.DEC || bb == base.HEX,
"strconv.stof64: base must be DEC or HEX");
if (s.len == 0) {
@@ -652,7 +650,7 @@ export fn stof32(s: str, b: base) (f32 | invalid | overflow) = {
} else if (bb == base.HEX_LOWER) {
bb = base.HEX;
};
os.assert(bb == base.DEC || bb == base.HEX,
assert(bb == base.DEC || bb == base.HEX,
"strconv.stof32: base must be DEC or HEX");
if (s.len == 0) {