os: graduate tryopen/trywrite/tryread to (T | oserror)

Final piece of the os module graduation: the three try* wrappers
move off the (T | str) placeholder shape. `oserror` becomes a real
Hare-style error type (`!i64` instead of plain `i64`), so it's
picked up by ?-propagation as the error half without callers having
to name it.

tryread:  (i64 | oserror)   was (i64 | str)
trywrite: (i64 | oserror)   was (i64 | str)
tryopen:  (i32 | oserror)   was (i32 | str)

Callsites updated: wwdump uses tryopen; the e2e trywrite probe
matches on os.oserror and validates -EBADF for a bad fd (-9 instead
of the old "write failed" string length).

selfhost/test/smoke.ww switched to raw os.open(2) instead of
os.tryopen for probe 7 — same reason as the os.readall switch in
the prior commit: probe 6 in 990_selfhost compiles smoke.ww
standalone, and cross-module type refs like `os.oserror` don't
resolve in that mode.
This commit is contained in:
2026-05-12 02:42:49 +09:00
parent 594a2bad62
commit d9041ab45e
7 changed files with 76 additions and 72 deletions

View File

@@ -747,26 +747,26 @@ static const struct row rows[] = {
" return acc;\n"
"};", 19 },
/* End-to-end stdlib usage: pull in lib/os and exercise the
* fallible API tryread/trywrite returning (i64 | str) over a
* real syscall. Validates that imported tagged-union returns
* survive the linker as well as the call ABI. */
* fallible API tryread/trywrite returning (i64 | oserror) over
* a real syscall. oserror carries -errno; on a bad fd we expect
* -EBADF (-9). */
{ "use os;\n"
"fn main() i32 = {\n"
" let buf: [3]u8;\n"
" buf[0] = 88: u8;\n"
" let ok: (i64 | str) = os.trywrite(1, buf.ptr, 1u64);\n"
" let bad: (i64 | str) = os.trywrite(999: i32, buf.ptr, 1u64);\n"
" let ok: (i64 | os.oserror) = os.trywrite(1, buf.ptr, 1u64);\n"
" let bad: (i64 | os.oserror) = os.trywrite(999: i32, buf.ptr, 1u64);\n"
" let acc: i32 = 0;\n"
" match (ok) {\n"
" case let n: i64 => acc += n: i32;\n"
" case let e: str => acc += -100;\n"
" case let e: os.oserror => acc += -100;\n"
" };\n"
" match (bad) {\n"
" case let n: i64 => acc += -100;\n"
" case let e: str => acc += e.len: i32;\n"
" case let e: os.oserror => acc += (- (e: i64)): i32;\n"
" };\n"
" return acc;\n"
"};", 13 }, /* 1 byte written to fd 1, plus len(\"write failed\")=12 */
"};", 10 }, /* 1 byte written + 9 (EBADF) */
/* strconv.stoi64: fallible signed decimal, graduated to
* (i64 | invalid | overflow). invalid carries the offending
* index; overflow is the void variant. */