wcc/ww: paramfieldsize sizes a tagged-union destructure binding

A tagged for-range destructure binding took the 8-byte default
(paramfieldsize had no tagged arm), skipping the full-extent copy —
the wwstage twin of the just-closed cstage destructure family. Read
the stamped tinfo size through the type table (twin of the slice
arm; cstage reads tp->type->size). Task #53.
This commit is contained in:
2026-06-13 00:07:36 +09:00
parent 2a2ac49c64
commit 347f6c42c8
5 changed files with 244 additions and 0 deletions

View File

@@ -39221,6 +39221,22 @@ fn paramfieldsize(t: *node) i32 = {
// tyslicesize() is the slice-header SSoT (rule-13); cstage reads the
// same width via tp->type->size (cmd/w6c/cgen.c N_FORRANGE).
if (k == nkind.N_TSLICE) { return tyslicesize(): i32; };
// #53: a tagged-union tuple-field carries its full box (tag + widest
// payload, slot-padded), NOT the 8B scalar default — a for-range
// destructure binding sized 8 loaded only the tag word (cs=56/ww=9, the
// cat-A repro). The box width is variant-dependent, so read it from the
// checker-stamped tinfo (rule-13): cstage's tp->type->size reads the same
// resolved width. The stamp already collapsed any alias, so this also
// covers an N_TNAME field naming a tagged union (paramfieldsize's no-`c`
// structural contract can't aliaslookup-chase the node). Mirrors the
// N_TSLICE arm's type-table SSoT.
let tgi: *tinfo = t.type_: *tinfo;
if (tgi != nil) {
tgi = tichase(tgi);
if (tgi != nil && tgi.kind == tykind.TY_TAGGED) {
return tgi.size: i32;
};
};
// #43 (F7-c4): a nested tuple field sizes as the sum of its element
// SLOTS — each element floored UP to one 8B eightbyte (str/slice keep
// their 24B header), per the tuple-slot ruling and tupeslot's

View File

@@ -3669,6 +3669,22 @@ fn paramfieldsize(t: *node) i32 = {
// tyslicesize() is the slice-header SSoT (rule-13); cstage reads the
// same width via tp->type->size (cmd/w6c/cgen.c N_FORRANGE).
if (k == nkind.N_TSLICE) { return tyslicesize(): i32; };
// #53: a tagged-union tuple-field carries its full box (tag + widest
// payload, slot-padded), NOT the 8B scalar default — a for-range
// destructure binding sized 8 loaded only the tag word (cs=56/ww=9, the
// cat-A repro). The box width is variant-dependent, so read it from the
// checker-stamped tinfo (rule-13): cstage's tp->type->size reads the same
// resolved width. The stamp already collapsed any alias, so this also
// covers an N_TNAME field naming a tagged union (paramfieldsize's no-`c`
// structural contract can't aliaslookup-chase the node). Mirrors the
// N_TSLICE arm's type-table SSoT.
let tgi: *tinfo = t.type_: *tinfo;
if (tgi != nil) {
tgi = tichase(tgi);
if (tgi != nil && tgi.kind == tykind.TY_TAGGED) {
return tgi.size: i32;
};
};
// #43 (F7-c4): a nested tuple field sizes as the sum of its element
// SLOTS — each element floored UP to one 8B eightbyte (str/slice keep
// their 24B header), per the tuple-slot ruling and tupeslot's

View File

@@ -39221,6 +39221,22 @@ fn paramfieldsize(t: *node) i32 = {
// tyslicesize() is the slice-header SSoT (rule-13); cstage reads the
// same width via tp->type->size (cmd/w6c/cgen.c N_FORRANGE).
if (k == nkind.N_TSLICE) { return tyslicesize(): i32; };
// #53: a tagged-union tuple-field carries its full box (tag + widest
// payload, slot-padded), NOT the 8B scalar default — a for-range
// destructure binding sized 8 loaded only the tag word (cs=56/ww=9, the
// cat-A repro). The box width is variant-dependent, so read it from the
// checker-stamped tinfo (rule-13): cstage's tp->type->size reads the same
// resolved width. The stamp already collapsed any alias, so this also
// covers an N_TNAME field naming a tagged union (paramfieldsize's no-`c`
// structural contract can't aliaslookup-chase the node). Mirrors the
// N_TSLICE arm's type-table SSoT.
let tgi: *tinfo = t.type_: *tinfo;
if (tgi != nil) {
tgi = tichase(tgi);
if (tgi != nil && tgi.kind == tykind.TY_TAGGED) {
return tgi.size: i32;
};
};
// #43 (F7-c4): a nested tuple field sizes as the sum of its element
// SLOTS — each element floored UP to one 8B eightbyte (str/slice keep
// their 24B header), per the tuple-slot ruling and tupeslot's