From fb4c567e0de7cfb3bcb419e3b3a0784d8b254c67 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sun, 24 May 2026 09:34:54 +0900 Subject: [PATCH] wcc: populate str.sub = u8 -- Phase 2 F1 foundation (both stages) str IS []u8 (#1 landed the 24B layout); F1 populates the element type so the step-3 checker collapse can read str.sub instead of special- casing TY_STR. No reader consumes str.sub yet, so this is byte-id- neutral: every shared ->sub reader a TY_STR value can reach is invariant under NULL->u8 -- u8 is unsigned + size-1, matching the prior NULL-defaults (size->1, signed->0, isstr/istagged->false); the only ->size derefs are guarded behind esz>1, which stays false for str. Verified inert: compiling a fixed source with the pre- and post-F1 compilers emits byte-identical asm on both stages; cross-stage byte-id holds and full make test (135 tests incl. 990-997) is green. cstage cmd/wcc/type.c, wwstage lib/ww/typ.ww; combined.ww regenerated via the canonical make path. --- cmd/wcc/type.c | 1 + lib/ww/typ.ww | 1 + selfhost/cmd/w6c/main.combined.ww | 1 + selfhost/cmd/wwdump/main.combined.ww | 1 + 4 files changed, 4 insertions(+) diff --git a/cmd/wcc/type.c b/cmd/wcc/type.c index ebafc41d..671118d4 100644 --- a/cmd/wcc/type.c +++ b/cmd/wcc/type.c @@ -64,6 +64,7 @@ typesinit(Arena *a) * Size sourced from the slice SSoT (type_slice) so str and []u8 can * never drift; no second hardcoded 24. */ ty_str = prim(a, TY_STR, "str", type_slice(a, ty_u8)->size, 8); + ty_str->sub = ty_u8; /* str IS []u8: element is u8 (Phase 2 F1) */ ty_err = prim(a, TY_ERR, "", 0, 1); ty_never = prim(a, TY_NEVER, "never", 0, 1); /* #29: predeclared `type nomem = !void;`. NAMED so variant_match diff --git a/lib/ww/typ.ww b/lib/ww/typ.ww index ad492bbc..60096c80 100644 --- a/lib/ww/typ.ww +++ b/lib/ww/typ.ww @@ -219,6 +219,7 @@ export fn typesinit(c: *tctx) void = { // cgdot mirror); retained here as a local until that lands. let u8slice: *tinfo = typeslice(c.tyu8); c.tystr = prim(tykind.TY_STR, "str", u8slice.size, 8u64); + c.tystr.sub = c.tyu8; // str IS []u8: element is u8 (Phase 2 F1) c.tyerr = prim(tykind.TY_ERR, "", 0u64, 1u64); c.tynever = prim(tykind.TY_NEVER, "never", 0u64, 1u64); diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 23723cd3..0c2e6ed6 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -6549,6 +6549,7 @@ export fn typesinit(c: *tctx) void = { // cgdot mirror); retained here as a local until that lands. let u8slice: *tinfo = typeslice(c.tyu8); c.tystr = prim(tykind.TY_STR, "str", u8slice.size, 8u64); + c.tystr.sub = c.tyu8; // str IS []u8: element is u8 (Phase 2 F1) c.tyerr = prim(tykind.TY_ERR, "", 0u64, 1u64); c.tynever = prim(tykind.TY_NEVER, "never", 0u64, 1u64); diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index e067c071..b94eab57 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -6549,6 +6549,7 @@ export fn typesinit(c: *tctx) void = { // cgdot mirror); retained here as a local until that lands. let u8slice: *tinfo = typeslice(c.tyu8); c.tystr = prim(tykind.TY_STR, "str", u8slice.size, 8u64); + c.tystr.sub = c.tyu8; // str IS []u8: element is u8 (Phase 2 F1) c.tyerr = prim(tykind.TY_ERR, "", 0u64, 1u64); c.tynever = prim(tykind.TY_NEVER, "never", 0u64, 1u64);