wcc/check: #20 reject overlong array-literal in a tuple element (wwstage)

An overlong array literal as a tuple element -- let t: ([2]int, i32) =
([1,2,3], 5) -- was silently accepted by wwstage; cstage loud-rejects it.
The #12+#106 over-fill coverage wired checkarrlitfits for direct-array,
slice and alias lhs positions but not the tuple-element position.

wwstage-only checker, reject-align: checkletassign gains an N_TTUPLE arm
that walks the lhs element types (llhs.list) lockstep with the rhs values
(n.rhs.list), calling the existing alias-aware checkarrlitfits per array
element (no-ops scalars, recurses nested arrays). cstage unchanged (w6c
md5 unchanged); reject-only, 990-997 8/8, no lib pin flips. test/wcc/832.

Two sibling tuple-element positions stay open (filed, not folded -- they
are reject-aligns on invalid programs, no selfhost byte-id impact): #25
tuple-RETURN overlong, #26 nested tuple-in-tuple.
This commit is contained in:
2026-06-09 02:34:33 +09:00
parent d8e2a0692c
commit dfdf99ffd8
5 changed files with 301 additions and 0 deletions

View File

@@ -14982,6 +14982,28 @@ fn checkletassign(c: *checker, n: *node) void = {
checkarrlitfits(c, n.lhs, n.rhs);
return;
};
// #20: array-typed TUPLE element with an overlong array literal —
// `let t:([2]int,i32) = ([1,2,3],5)` was silently accepted (the tuple
// position wasn't wired to checkarrlitfits, unlike the direct-array
// let above). Walk declared-tuple element types vs rhs values; over-
// fill-check each (checkarrlitfits chases aliases #106, recurses
// nested arrays #251, and no-ops on non-array elements). Mirror
// cstage's tuple element-wise reject. No early return — the rest of
// checkletassign still runs for the tuple. N_TTUPLE elements wrap
// their type on .lhs (N_TPARAM chain, stamptuplebinds:311); the
// N_TUPLE rhs values chain directly on .list.
if (llhs != nil && llhs.kind == nkind.N_TTUPLE
&& n.rhs.kind == nkind.N_TUPLE) {
let dt: *node = llhs.list;
let vt: *node = n.rhs.list;
for (dt != nil && vt != nil) {
if (vt.kind == nkind.N_ARRLIT) {
checkarrlitfits(c, dt.lhs, vt);
};
dt = dt.next;
vt = vt.next;
};
};
// #25/#31: an array literal initialising a SLICE local. Re-stamp the
// literal as [count]T (the slice element) so the #258 borrow's exact-
// element typeeq holds and the cgen N_SLICE-over-N_ARRLIT arm reads the

View File

@@ -4701,6 +4701,28 @@ fn checkletassign(c: *checker, n: *node) void = {
checkarrlitfits(c, n.lhs, n.rhs);
return;
};
// #20: array-typed TUPLE element with an overlong array literal —
// `let t:([2]int,i32) = ([1,2,3],5)` was silently accepted (the tuple
// position wasn't wired to checkarrlitfits, unlike the direct-array
// let above). Walk declared-tuple element types vs rhs values; over-
// fill-check each (checkarrlitfits chases aliases #106, recurses
// nested arrays #251, and no-ops on non-array elements). Mirror
// cstage's tuple element-wise reject. No early return — the rest of
// checkletassign still runs for the tuple. N_TTUPLE elements wrap
// their type on .lhs (N_TPARAM chain, stamptuplebinds:311); the
// N_TUPLE rhs values chain directly on .list.
if (llhs != nil && llhs.kind == nkind.N_TTUPLE
&& n.rhs.kind == nkind.N_TUPLE) {
let dt: *node = llhs.list;
let vt: *node = n.rhs.list;
for (dt != nil && vt != nil) {
if (vt.kind == nkind.N_ARRLIT) {
checkarrlitfits(c, dt.lhs, vt);
};
dt = dt.next;
vt = vt.next;
};
};
// #25/#31: an array literal initialising a SLICE local. Re-stamp the
// literal as [count]T (the slice element) so the #258 borrow's exact-
// element typeeq holds and the cgen N_SLICE-over-N_ARRLIT arm reads the

View File

@@ -14982,6 +14982,28 @@ fn checkletassign(c: *checker, n: *node) void = {
checkarrlitfits(c, n.lhs, n.rhs);
return;
};
// #20: array-typed TUPLE element with an overlong array literal —
// `let t:([2]int,i32) = ([1,2,3],5)` was silently accepted (the tuple
// position wasn't wired to checkarrlitfits, unlike the direct-array
// let above). Walk declared-tuple element types vs rhs values; over-
// fill-check each (checkarrlitfits chases aliases #106, recurses
// nested arrays #251, and no-ops on non-array elements). Mirror
// cstage's tuple element-wise reject. No early return — the rest of
// checkletassign still runs for the tuple. N_TTUPLE elements wrap
// their type on .lhs (N_TPARAM chain, stamptuplebinds:311); the
// N_TUPLE rhs values chain directly on .list.
if (llhs != nil && llhs.kind == nkind.N_TTUPLE
&& n.rhs.kind == nkind.N_TUPLE) {
let dt: *node = llhs.list;
let vt: *node = n.rhs.list;
for (dt != nil && vt != nil) {
if (vt.kind == nkind.N_ARRLIT) {
checkarrlitfits(c, dt.lhs, vt);
};
dt = dt.next;
vt = vt.next;
};
};
// #25/#31: an array literal initialising a SLICE local. Re-stamp the
// literal as [count]T (the slice element) so the #258 borrow's exact-
// element typeeq holds and the cgen N_SLICE-over-N_ARRLIT arm reads the