Commit Graph

4 Commits

Author SHA1 Message Date
594a2bad62 wcc: Hare-style !T error marker on tagged-union variants
A type prefixed with `!` is flagged as an error variant. When any
variant in a tagged union carries the flag, `?` propagation uses
those (and only those) as the error subset; the unflagged variant
is the success type. The legacy "first variant = success" rule still
applies when no `!`-flag is present, so existing code keeps working.

- TK_NOT in parsetype → N_TBANG wrapper (lhs = inner type expr).
  Appended to Nkind tail for wwdump-diff byte stability.
- resolve_type N_TBANG: wraps primitives in a fresh Type copy so the
  iserror bit doesn't taint shared globals like ty_str/ty_i32; flips
  the bit in place on NAMED (already unique per alias decl).
- Type.iserror; type_named and typedecl inherit it from under.
- New check.c helpers: tagged_has_errflag, tagged_is_error_variant,
  tagged_success_type. N_TRYPROP uses them to find the error subset
  and verify each error variant is propagatable to the enclosing
  return.
- cgen mirrors with cg_tagged_success_tag + cg_variant_is_error.
  `?` compares AX against the success tag (no longer always 0) and
  remaps each error variant's tag for the enclosing fn. `!` aborts
  on any non-success tag.

strconv.invalid and strconv.overflow now use `!`-flagged shape
(`!i32` and `!void`) — visible signal in the API surface that they
are error types, matching Hare. The (i64 | invalid | overflow)
return shape and behavior are unchanged for callers; their match
arms still bind the same way.

Selfhost: lib/ww/parse/parse.ww recognises `!T` and emits N_TBANG.
The selfhost typechecker and cgen ignore the flag — none of the
selfhost sources use `!`, so byte-identity gates are unaffected.
The selfhost mirror catches up when there's a source using it.
2026-05-12 02:39:54 +09:00
41a82021a3 wcc: ? error-subset propagation typecheck + tag remap
`expr?` previously did a brain-dead RET through whatever AX/DX/CX
held — only safe when operand and enclosing fn had identical variant
ordering. Tests relied on that alignment by construction.

Now:
- Typecheck: each non-first variant of operand must appear as a
  variant of the enclosing fn's return tagged union. Enclosing must
  itself be tagged (a non-tagged return has no slot for errors to
  land in).
- Cgen: on tag != 0, walk operand's error variants and emit a
  conditional tag remap (cmp/jne/mov/jmp) for any whose index in
  enclosing differs from operand's. Identity cases emit nothing,
  so same-shape operands cost zero extra instructions.

Selfhost cgen doesn't implement N_TRYPROP at all (no selfhost source
uses `?`); byte-identity tests still pass.

One existing e2e row used `?` with main returning i32 — relied on
the old loose semantics. Switched to `!` (abort-on-error); it was
exercising success-unwrap, not propagation.
2026-05-12 01:40:02 +09:00
fa070b6d07 wcc: tagged-union foundations (never, void, flatten, exhaust)
- `never` bottom type: TY_NEVER, assignable to anything; size 0.
- Type-set normalization for N_TTAGGED in resolve_type:
  - flatten nested anonymous (A|B)|C → (A|B|C); named aliases stay
    nominal (not flattened through)
  - dedup duplicates (NAMED pointer-id; others structural)
  - drop `never` variants
  - collapse single-element set: (T|never) → T, (T|T) → T
- Match exhaustiveness: error when a variant is unhandled and no
  default arm covers it. Multi-pattern `case T1 | T2 =>` counts
  each alt.
- (T | void) optionals: bare `return;` from a tagged-union-returning
  fn emits the void variant's tag (payload undefined; void size 0).

selfhost mirrored: TY_NEVER constant + tynever in tctx + seedprim
entry; voidvariantindex helper; cgreturn bare-return handling.
2026-05-12 01:31:35 +09:00
2c33228b7e ww: rename toolchain to w-prefix + hare-style build/run/test driver
Plan 9-style w-prefix on the per-arch tools, disambiguating from the
real Plan 9 6c/6a/6l in ref/plan9front/:

    cmd/wwc/      → cmd/wcc/        libwwc.a → libwcc.a
    cmd/6{c,a,l}  → cmd/w6{c,a,l}   binary names too
    test/wwc/     → test/wcc/       6 test files w/ w6 prefix
    selfhost/cmd  mirror in lockstep
    bootstrap/amd64/{w6c,w6a,w6l}   snapshot binaries (gitignored)
    WW_6{C,A,L}   → WW_W6{C,A,L}    env-var overrides

Plan 9 source-tree refs ("Plan 9 6c shape", ref/plan9front/, etc.)
preserved. Hare-style driver, both C and ww sides:

    ww test [path]   discover *_test.ww in a directory module, run
                     each; single-file mode for `ww test foo.ww`
    Module-by-name   `ww build foo` resolves to foo.ww or foo/foo.ww
                     via search path (cwd : -I dirs : $WW_LIB)
    Default-to-cwd   `ww build` / `ww test` build the cwd module
    Run pass-through `ww run path arg1 arg2` reaches the program

lib/os: getcwd (79) and getdents64 (217) syscalls power `.` resolution
and directory enumeration on the ww side.

Makefile: wwstage tool deps now include lib/os/os.ww (+ lib/strconv
for wwdump_ww) so lib/* edits force their rebuild instead of leaving
stale binaries — surfaced when test 995 first failed against a stale
w6c_ww built before the lib/os additions.

Test 993 byte-identical parity gate (C-side ww vs ww-side ww_ww on a
build corpus) stays green; all 19 tests pass.
2026-05-11 13:49:27 +09:00