w6c+wcc: widen struct/tagged-subset, parse ... spread

Three tagged-union gaps:

  1. Struct-payload widening was broken at every site (call, let,
     assign, return, struct-field init). cg_widen_tagged_store now
     materialises str / scalar / struct-lit / struct-ident / tagged
     payloads at slot+8+field_off and writes the tag last. Call sites
     route through cg_widen_tagged_push (scratch slot + push high→low).

  2. Tagged → wider tagged widening forwarded the source tag verbatim.
     cg_widen_tag_remap emits a CMPQ-chain switch that translates each
     source variant index to the destination's, then zero-pads to the
     wider slot. type_eq grew a TY_TAGGED arm (was returning 1 for any
     two unions); type_assignable now accepts variant-subset and
     rejects the rest.

  3. `(...inner | T)` spread parses (cmd/wcc/parse.c, lib/ww/parse).
     Marks Node.op = TK_ELLIPSIS; resolve_type unwraps NAMED + flattens
     when the spread bit is set so aliases inline like Hare's
     tagged_type unwrap flag.

Selfhost mirror: spread parser ported. Cgen widen helpers not yet
mirrored — wwstage stays byte-identical to cstage on the existing
test corpus, but will emit wrong asm if user code uses the new
patterns (probe sp2 shows the divergence).

700_e2e: 9 new rows covering call/let/assign/return × struct +
tagged subset, plus the spread-flatten case.
This commit is contained in:
2026-05-13 05:30:20 +09:00
parent 47d75d9b59
commit 9133251269
8 changed files with 562 additions and 161 deletions

View File

@@ -323,9 +323,16 @@ resolve_type(Checker *c, Node *n)
for (Node *e = n->list; e; e = e->next) {
Type *vt = resolve_type(c, e);
if (vt == ty_never) continue;
if (vt && vt->kind == TY_TAGGED) {
/* flatten anonymous nested tagged */
for (Tparam *src = vt->params; src; src = src->next) {
int spread = (e->op == TK_ELLIPSIS);
/* `...inner` spread: flatten the variants of the
* (possibly NAMED) inner tagged union into the
* enclosing union — matches Hare's parse-time
* unwrap flag on each tagged_type entry. */
Type *vu = spread && vt && vt->kind == TY_NAMED
? vt->under : vt;
if (vu && vu->kind == TY_TAGGED &&
(spread || vt->kind == TY_TAGGED)) {
for (Tparam *src = vu->params; src; src = src->next) {
Type *st = src->type;
if (st == ty_never) continue;
if (variant_present(head, st)) continue;