Files
ww/test/lang/idxfield_compound_test.ww
Hojun-Cho 057e805cf0 test: migrate dotfield/idxfield compound-assign to @test + runww rejects, retire C twins (fold-3)
949_dotfield_compound + 949_idxfield_compound are one bug class (#133-lineage compound-assign load-op-store on field lvalues; #34/#33, #263 carve-out) sharing the combine + hard-error path, so the two C carriers fuse into one commit: 26 value rows -> test/lang @test row-tables (primitive-only asserts), 8 reject rows -> runww //ww:error dual-stage carriers. byteid floor 50->52.
2026-06-22 16:34:33 +09:00

117 lines
3.3 KiB
Plaintext

// idxfield_compound_test — indexed-element field compound-assign (#33, #263
// both stages), migrated from test/wcc/949_idxfield_compound_run.c. A compound
// assign on an indexed-element FIELD lvalue (`arr[i].field OP= v`) must do a
// real LOAD-OP-STORE for ALL ten integer ops, not silently no-op the four the
// arm never wired (SLASHEQ/PERCENTEQ/LSHIFTEQ/RSHIFTEQ loaded the old value
// into AX, fired no combine, and stored AX back — a silent no-op in BOTH
// stages, gate-blind/byte-identical). Every row init-poisons xs[0].f with a
// value != the expected result, runs the op, reads the field back, and asserts
// a sibling slot (xs[0].g or xs[1].f) is UNTOUCHED to catch an over-wide /
// wrong-offset store. PRIMITIVE-only asserts (no fmt/strconv) so a co-
// miscompile in the assert path cannot mask the bug. The matrix covers
// + * / % << >> across i32/i64/u32 fields and a via-ptr element ([N]*S); the
// plain-assign control pins the ASSIGN path the fix must leave unchanged. T2
// keeps cs==ww.
package idxfield_compound_test;
type S32 = struct { f: i32, g: i32 };
type S64 = struct { f: i64, g: i64 };
type Su32 = struct { f: u32, g: u32 };
@test fn fld_i32_pluseq() void = {
let xs: [2]S32 = [S32{f=100, g=0}, S32{f=0, g=0}];
xs[0].f += 50;
assert(xs[0].f == 150);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};
@test fn fld_i64_stareq() void = {
let xs: [2]S64 = [S64{f=6i64, g=0i64}, S64{f=0i64, g=0i64}];
xs[0].f *= 7i64;
assert(xs[0].f == 42i64);
assert(xs[0].g == 0i64);
assert(xs[1].f == 0i64);
};
@test fn fld_i32_slasheq() void = {
let xs: [2]S32 = [S32{f=100, g=0}, S32{f=0, g=0}];
xs[0].f /= 4;
assert(xs[0].f == 25);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};
@test fn fld_i32_slasheq_neg() void = {
let xs: [2]S32 = [S32{f=-17, g=0}, S32{f=0, g=0}];
xs[0].f /= 4;
assert(xs[0].f == -4);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};
@test fn fld_u32_slasheq() void = {
let xs: [2]Su32 = [Su32{f=100u32, g=0u32}, Su32{f=0u32, g=0u32}];
xs[0].f /= 4u32;
assert(xs[0].f == 25u32);
assert(xs[0].g == 0u32);
assert(xs[1].f == 0u32);
};
@test fn fld_i32_percenteq() void = {
let xs: [2]S32 = [S32{f=17, g=0}, S32{f=0, g=0}];
xs[0].f %= 5;
assert(xs[0].f == 2);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};
@test fn fld_u32_percenteq() void = {
let xs: [2]Su32 = [Su32{f=100u32, g=0u32}, Su32{f=0u32, g=0u32}];
xs[0].f %= 7u32;
assert(xs[0].f == 2u32);
assert(xs[0].g == 0u32);
assert(xs[1].f == 0u32);
};
@test fn fld_i32_lshifteq() void = {
let xs: [2]S32 = [S32{f=3, g=0}, S32{f=0, g=0}];
xs[0].f <<= 4;
assert(xs[0].f == 48);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};
@test fn fld_u32_rshifteq() void = {
let xs: [2]Su32 = [Su32{f=200u32, g=0u32}, Su32{f=0u32, g=0u32}];
xs[0].f >>= 2u32;
assert(xs[0].f == 50u32);
assert(xs[0].g == 0u32);
assert(xs[1].f == 0u32);
};
@test fn fld_i32_rshifteq_neg() void = {
let xs: [2]S32 = [S32{f=-16, g=0}, S32{f=0, g=0}];
xs[0].f >>= 2;
assert(xs[0].f == -4);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};
@test fn fld_viaptr_pluseq() void = {
let a: S32 = S32{f=10, g=0};
let xs: [2]*S32 = [&a, &a];
xs[0].f += 5;
assert(a.f == 15);
assert(a.g == 0);
};
@test fn fld_plain_assign_ctrl() void = {
let xs: [2]S32 = [S32{f=1, g=0}, S32{f=0, g=0}];
xs[0].f = 99;
assert(xs[0].f == 99);
assert(xs[0].g == 0);
assert(xs[1].f == 0);
};