wcc/cgen: #47 gap-A tuple-in-union tagged-element store (both-stage)

A tuple containing a tagged-union element, used as a union member
(e.g. ((void|size),(void|size),size) | error), loud-stopped in the
cgen return-store: the tuple-in-union store walk had scalar/float/
str/slice element arms but no TY_TAGGED-element arm. A PLAIN
tuple-in-union already worked -- the blocker was the tagged element.

Add the recursive two-level widen arm at both stages
(cg_widen_tagged_store / cgwidentaggedstorebp): for each tagged
element, re-enter the tagged-box store (inner tag@slot+0,
payload@slot+8) at the element's tuple-payload offset, then stamp the
outer tuple tag. Slot strides come from the type table
(roundup8(eu->size)) -- the checker already sizes the shape correctly
(tuple->size measured 40, union box 48; check.c:715-720). The
recursion descends a finite type tree (a tagged element is never a
tuple literal, so it can't re-enter the tuple arm); unsupported
deeper nesting still louds via the existing size/tag guards.

Both stages get the same arm -> byte-id (990-997 green; additive,
bootstrap-neutral). cstage runs the full b1c shape
(construct+return+match-extract) as the runtime reference; wwstage's
store rides on byte-id until gap-B. gap-B (wwstage checker
match-acceptance of the tuple-with-tagged case pattern) is a separate
commit -- wwstage still louds the match honestly at the checker.
Pin 944_tuple_tagged_union_run.
This commit is contained in:
2026-06-06 16:57:42 +09:00
parent 351abb0ab3
commit 6a5bb3efc9
6 changed files with 429 additions and 41 deletions

View File

@@ -2768,16 +2768,18 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src,
* SysV eightbyte tuple classification is a deferred follow-up. */
int total = 0;
for (Node *e = tupsrc->list; e; e = e->next) {
/* #22a (rule 7): a tagged element's box can't ride
* the scalar/wide store arms belowpre-guard it
* silently stored word0. Nested tagged-in-tuple-in-
* union packing is the #242/#22b family. */
/* #47 gap-A: a tagged element rides its OWN box
* (tag + payload, roundup8) per tuple slotNOT one
* 8B word. Mirror the checker's N_TTUPLE accumulation
* (check.c:715-720): aggregate/tagged elem += its
* box size rounded to 8; the store loop below boxes it
* recursively (two-level widen). */
Type *eu = type_chase_named(e->type);
if (eu && eu->kind == TY_TAGGED)
fatal("cg_widen_tagged_store: tagged element "
"in a tuple-in-union payload unwired "
"(see #242/#22b)");
total += (node_isstr(e) || node_isslice(e)) ? 24 : 8;
total += ((int)eu->size + 7) & ~7;
else
total += (node_isstr(e) || node_isslice(e)) ?
24 : 8;
}
if (8 + total > sz)
fatal("cg_widen_tagged_store: tuple-in-union payload needs "
@@ -2789,6 +2791,20 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src,
amem(D_BP, write_off + k));
int foff = 0;
for (Node *e = tupsrc->list; e; e = e->next) {
/* #47 gap-A: a tagged element is its own tag+payload
* box. Recurse so the inner box (tag@slot+0,
* payload@slot+8) is built at the element's tuple-
* payload offset, exactly as a top-level tagged-store
* does — two-level widen (inner boxes here, outer tuple
* tag stamped below). slot stride = roundup8(box). */
Type *eu = type_chase_named(e->type);
if (eu && eu->kind == TY_TAGGED) {
int ebox = ((int)eu->size + 7) & ~7;
cg_widen_tagged_store(c, locals_p, e->type, e,
D_BP, write_off + 8 + foff, ebox);
foff += ebox;
continue;
}
int e_isf32 = 0;
int isflt = fld_isfloat(e->type, &e_isf32);
int wide = node_isstr(e) || node_isslice(e);