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

@@ -145,7 +145,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
export fn ltrim(in: []u8, trim: u8...) []u8 = {
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
let i: i32 = 0;
for (i < in.len && contains(trim, in[i])) { i += 1; };
let r: []u8;
@@ -160,7 +160,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
// the equivalent termination is spelled `i >= 0` explicitly.
export fn rtrim(in: []u8, trim: u8...) []u8 = {
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
let i: i32 = in.len - 1;
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
let r: []u8;
@@ -228,8 +228,8 @@ export fn zero(s: []u8) void = {
// `delim` is borrowed; caller keeps it valid for the tokenizer's
// lifetime. ref/hare/bytes/tokenize.ha:22.
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
os.assert((in.len: i64) < types.I64_MAX,
assert(delim.len > 0, "bytes.tokenize called with empty slice");
assert((in.len: i64) < types.I64_MAX,
"bytes.tokenize: input length exceeds I64_MAX");
let t: tokenizer;
t.in = in;
@@ -245,8 +245,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
// rtokenize — reverse-direction tokenize. First next_token yields the
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
os.assert((in.len: i64) < types.I64_MAX,
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
assert((in.len: i64) < types.I64_MAX,
"bytes.rtokenize: input length exceeds I64_MAX");
let t: tokenizer;
t.in = in;
@@ -400,7 +400,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
//
// ref/hare/bytes/tokenize.ha:156.
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
os.assert(delim.len > 0,
assert(delim.len > 0,
"bytes.splitn must not be called with an empty delimiter");
let toks: [][]u8;
toks.ptr = nil: *[]u8;
@@ -438,7 +438,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
//
// ref/hare/bytes/tokenize.ha:186.
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
os.assert(delim.len > 0,
assert(delim.len > 0,
"bytes.rsplitn called with empty delimiter");
let toks: [][]u8;
toks.ptr = nil: *[]u8;
@@ -507,7 +507,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
let ln: i32 = match (delim) {
case let c: u8 => yield 1i32;
case let sub: []u8 => {
os.assert(sub.len > 0,
assert(sub.len > 0,
"bytes.cut called with empty delimiter");
yield sub.len;
};
@@ -531,7 +531,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
let ln: i32 = match (delim) {
case let c: u8 => yield 1i32;
case let sub: []u8 => {
os.assert(sub.len > 0,
assert(sub.len > 0,
"bytes.rcut called with empty delimiter");
yield sub.len;
};