Files
ww/test/lang/idxdot_aggcopy_test.ww
Hojun-Cho 84206ff4ed w6c: resolve ptr-to-array and slice-element aggregate sources (task #6 residue)
The two loud siblings filed in d3822d77: (a) an auto-deref *[N]T
indexed base (hs[k].result) failed cgplaceaddr's N_INDEX arm, which
knew only TY_SLICE/TY_ARRAY bases — add the one-pointer hop (the
(*hs)[k] form made implicit; load shape is the slice .ptr word's);
(b) a bare slice-element aggregate source (use(sl[k])) fell off
aggarg_srcaddr's ident-array-only N_INDEX arm into the #271 loud
stop — route the miss through the same cgplaceaddr fallback the
N_DOT arm uses. Both stages, byte-identical (probe matrix: let-copy,
field-assign, call-arg, return, indexed-store all IDENT).

After this, every ADDRESSABLE aggregate source resolves: ident
(local/module-let), deref, dot-chain, and index over array/slice/
ptr-array spines recurse through cgplaceaddr; the remaining loud
paths are rvalue sources (#40 family) and the #274 const-def arg,
both documented divergences. 8 rows added to idxdot_aggcopy_test.
2026-08-08 19:08:19 +09:00

217 lines
4.6 KiB
Plaintext

// idxdot_aggcopy_test — aggregate copies whose SOURCE is an
// indexed-then-dotted chain (elem[k].field). The dot-chain address
// walker has no index hop (AX-clean spill contract), so these shapes
// ride the generic place-resolver fallback (task #6); the indexed
// element-store row pins the once-SILENT unchecked-walker site that
// copied through a stale SI in both stages.
package idxdot_aggcopy_test;
type inner = struct {
a: i64,
b: i64,
};
type handle = struct {
id: i64,
result: inner,
};
type mid = struct {
pad: i64,
in_: inner,
};
type outer = struct {
tag: i64,
m: mid,
};
fn mk() [4]handle = {
let hs: [4]handle;
hs[0] = handle{id = 1, result = inner{a = 1, b = 2}};
hs[1] = handle{id = 2, result = inner{a = 3, b = 4}};
hs[2] = handle{id = 9, result = inner{a = 11, b = 31}};
hs[3] = handle{id = 4, result = inner{a = 5, b = 6}};
return hs;
};
fn use(v: inner) i64 = {
return v.a + v.b;
};
@test fn letcopy() void = {
let hs: [4]handle = mk();
let k: i64 = 2;
let r: inner = hs[k].result;
assert(r.a == 11);
assert(r.b == 31);
};
@test fn callarg() void = {
let hs: [4]handle = mk();
let k: i64 = 2;
assert(use(hs[k].result) == 42);
};
type bag = struct {
n: i64,
res: inner,
};
@test fn fieldassign() void = {
let hs: [4]handle = mk();
let k: i64 = 2;
let g: bag;
g.n = 0;
g.res = hs[k].result;
assert(g.res.a == 11);
assert(g.res.b == 31);
};
fn pickresult(hs: *[4]handle, k: i64) inner = {
return (*hs)[k].result;
};
@test fn aggreturn() void = {
let hs: [4]handle = mk();
let r: inner = pickresult(&hs, 2);
assert(r.a == 11);
assert(r.b == 31);
};
@test fn slicebase() void = {
let hs: [4]handle = mk();
let sl: []handle = hs[0:4];
let k: i64 = 2;
assert(use(sl[k].result) == 42);
};
@test fn nesteddot() void = {
let os_: [3]outer;
os_[1] = outer{tag = 7, m = mid{pad = 0, in_ = inner{a = 20, b = 22}}};
let k: i64 = 1;
let l: inner = os_[k].m.in_;
assert(l.a == 20);
assert(l.b == 22);
};
// the once-silent shape: indexed element STORE from an indexed-dotted
// source (unchecked walker left SI stale; both stages copied garbage).
@test fn indexedstore() void = {
let hs: [4]handle = mk();
let out: [3]inner;
out[0] = inner{a = 1, b = 1};
out[1] = inner{a = 2, b = 2};
out[2] = inner{a = 3, b = 3};
let k: i64 = 2;
let j: i64 = 1;
out[j] = hs[k].result;
assert(out[1].a == 11);
assert(out[1].b == 31);
assert(out[0].a == 1);
assert(out[2].a == 3);
};
@test fn identreassign() void = {
let hs: [4]handle = mk();
let k: i64 = 2;
let r: inner = inner{a = 0, b = 0};
r = hs[k].result;
assert(r.a == 11);
assert(r.b == 31);
};
// control: the LHS twin (store INTO elem[k].field) was already wired.
@test fn lhsstore() void = {
let hs: [4]handle = mk();
let k: i64 = 0;
let r: inner = inner{a = 40, b = 41};
hs[k].result = r;
assert(hs[0].result.a == 40);
assert(hs[0].result.b == 41);
};
// task #6 siblings (the d3822d77 loud residue): a *[N]T indexed base
// auto-derefs through cgplaceaddr's pointer hop, and a bare slice
// element rides aggarg_srcaddr's place-resolver fallback.
@test fn ptrbaseletcopy() void = {
let hs: [4]handle = mk();
let hp: *[4]handle = &hs;
let k: i64 = 2;
let r: inner = hp[k].result;
assert(r.a == 11);
assert(r.b == 31);
};
@test fn ptrbasecallarg() void = {
let hs: [4]handle = mk();
let hp: *[4]handle = &hs;
let k: i64 = 2;
assert(use(hp[k].result) == 42);
};
fn pickptr(hp: *[4]handle, k: i64) inner = {
return hp[k].result;
};
@test fn ptrbasereturn() void = {
let hs: [4]handle = mk();
let r: inner = pickptr(&hs, 2);
assert(r.a == 11);
assert(r.b == 31);
};
@test fn ptrbasefieldassign() void = {
let hs: [4]handle = mk();
let hp: *[4]handle = &hs;
let k: i64 = 2;
let g: bag;
g.n = 0;
g.res = hp[k].result;
assert(g.res.a == 11);
assert(g.res.b == 31);
};
@test fn sliceelemletcopy() void = {
let hs: [4]handle = mk();
let sl: []handle = hs[0:4];
let k: i64 = 2;
let e: handle = sl[k];
assert(e.id == 9);
assert(e.result.a == 11);
};
@test fn sliceelemcallarg() void = {
let hs: [4]handle = mk();
let sl: []handle = hs[0:4];
let k: i64 = 2;
assert(usehandle(sl[k]) == 51);
};
fn usehandle(h: handle) i64 = {
return h.id + h.result.a + h.result.b;
};
fn pickelem(sl: []handle, k: i64) handle = {
return sl[k];
};
@test fn sliceelemreturn() void = {
let hs: [4]handle = mk();
let sl: []handle = hs[0:4];
let e: handle = pickelem(sl, 2);
assert(e.id == 9);
assert(e.result.b == 31);
};
@test fn sliceelemindexedstore() void = {
let hs: [4]handle = mk();
let sl: []handle = hs[0:4];
let out: [2]inner;
let j: i64 = 0;
out[j] = sl[2].result;
assert(out[0].a == 11);
assert(out[0].b == 31);
};