wcc/cgen: GAP-A.len def-global array .len — def-twin cgdot arm (#7 lineage, wwstage align-up)

wwstage .len on a def-global array fell to the cgdot SB-fallback (w6l: undefined reference to 'len') — the #7 let-array arm gates on letvartnode (c.lets only), so def-globals (c.defs) missed it. Add a def .len-only arm in cgdot using the existing defvartnode (the def-side mirror of letvartnode), emitting the length immediate from the #11-stamped N_TARRAY length child. cstage cgen.c was already correct, so this is a wwstage-only source change: w6c unchanged, w6c_ww + wwdump regen'd (they embed the wcc cgen).

.ptr (cstage itself buggy — emits LEAQ (BP), filed GAP-A.ptr) and .cap (wwstage silent garbage; arrays have no cap, filed GAP-A.cap) are NOT folded (rule-11, separate concerns). Pin: table-driven test/wcc/816_def_arr_len (def [3] + [_] inferred + 1-elem + u8 stride .len, both stages + byte-id), teeth-proven.
This commit is contained in:
2026-06-08 16:19:29 +09:00
parent c35034df3f
commit 7b0e09e065
5 changed files with 342 additions and 0 deletions

View File

@@ -24962,6 +24962,37 @@ fn cgdot(c: *cgen, n: *node) void = {
};
};
};
// GAP-A (#7 def-twin): `def NAME: [N]T = arrlit;` `.len` = static
// elem count. The let-global arm above resolves via letvartnode
// (c.lets only); a def lives in c.defs, misses it, and falls to the
// SB fallback → MOVQ len(SB) (w6l: undefined 'len'). cstage cgen.c
// emits MOVQ $alen here. defvartnode is the def-side mirror of
// letvartnode (returns dtnode = the N_TARRAY whose .rhs length child
// is #11-stamped). `.ptr`/`.cap` are NOT mirrored: cstage's def .ptr
// is itself buggy (LEAQ (BP), task GAP-A.ptr) and arrays have no
// .cap (cstage rejects, task GAP-A.cap).
if (lhs != nil) {
if (lhs.kind == nkind.N_IDENT) {
if (streq(fld, "len")) {
let dtn: *node = defvartnode(c, lhs.str);
if (dtn != nil) {
if (dtn.kind == nkind.N_TARRAY) {
let lenn: *node = dtn.rhs;
let alen: i64 = 0i64;
if (lenn != nil) {
if (lenn.kind == nkind.N_INTLIT) {
alen = lenn.uval: i64;
};
};
emitline("\tMOVQ\t$");
emitint(alen);
emitline(", AX\n");
return;
};
};
};
};
};
// Top-level TUPLE global positional read (C-t3, #48): `g.N` —
// LEAQ name(SB) into CX, then load at the element's SLOT offset
// (C-t0 layout), the element's natural width. Mirrors the local