Files
ww/test/lang/dotfield_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

124 lines
3.1 KiB
Plaintext

// dotfield_compound_test — single-dot field compound-assign (#34, #263 both
// stages), migrated from test/wcc/949_dotfield_compound_run.c. A compound
// assign on a single-dot field lvalue (`s.f OP= v`, `p.f OP= v`, `g.f OP= v`,
// `sl.len OP= v`) must do a real LOAD-OP-STORE for ALL ten integer ops, not
// silently demote a non-+=/-= op to a plain `s.f = rhs` (the prior bug: *= /=
// %= &= |= ^= <<= >>= left old-in-BX/rhs-in-AX then stored AX, so `s.f *= 3`
// compiled to `s.f = 3`, gate-blind/byte-identical). Every row init-poisons
// the field with a value != the expected result, runs the op, reads the field
// back, and asserts the sibling field `g` (or the slice `.cap`) 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 int/i32/u32 fields, a via-ptr base, a
// global struct field, and the str/slice `.len` pseudo-field; the plain-assign
// control pins the ASSIGN path the fix must leave unchanged. T2 keeps cs==ww.
package dotfield_compound_test;
type Sii = struct { f: int, g: int };
type S32 = struct { f: i32, g: i32 };
type Su32 = struct { f: u32, g: u32 };
let gs: Sii = Sii{f=20, g=0};
fn bump(p: *Sii) void = { p.f *= 3; };
@test fn dotfld_pluseq_ctrl() void = {
let s: Sii = Sii{f=10, g=0};
s.f += 5;
assert(s.f == 15);
assert(s.g == 0);
};
@test fn dotfld_stareq() void = {
let s: Sii = Sii{f=5, g=0};
s.f *= 3;
assert(s.f == 15);
assert(s.g == 0);
};
@test fn dotfld_slasheq_signed() void = {
let s: Sii = Sii{f=100, g=0};
s.f /= 4;
assert(s.f == 25);
assert(s.g == 0);
};
@test fn dotfld_slasheq_neg() void = {
let s: S32 = S32{f=-17, g=0};
s.f /= 4;
assert(s.f == -4);
assert(s.g == 0);
};
@test fn dotfld_slasheq_unsigned() void = {
let s: Su32 = Su32{f=100u32, g=0u32};
s.f /= 4u32;
assert(s.f == 25u32);
assert(s.g == 0u32);
};
@test fn dotfld_percenteq() void = {
let s: Sii = Sii{f=17, g=0};
s.f %= 5;
assert(s.f == 2);
assert(s.g == 0);
};
@test fn dotfld_lshifteq() void = {
let s: Sii = Sii{f=3, g=0};
s.f <<= 4;
assert(s.f == 48);
assert(s.g == 0);
};
@test fn dotfld_rshifteq_neg() void = {
let s: S32 = S32{f=-16, g=0};
s.f >>= 2;
assert(s.f == -4);
assert(s.g == 0);
};
@test fn dotfld_rshifteq_unsigned() void = {
let s: Su32 = Su32{f=200u32, g=0u32};
s.f >>= 2u32;
assert(s.f == 50u32);
assert(s.g == 0u32);
};
@test fn dotfld_viaptr_stareq() void = {
let a: Sii = Sii{f=4, g=0};
bump(&a);
assert(a.f == 12);
assert(a.g == 0);
};
@test fn dotfld_global_slasheq() void = {
gs.f /= 4;
assert(gs.f == 5);
assert(gs.g == 0);
};
@test fn dotfld_pseudo_len_minuseq() void = {
let buf: [8]u8 = [1u8,2u8,3u8,4u8,5u8,6u8,7u8,8u8];
let sl: []u8 = buf[0:8];
sl.len -= 3;
assert(sl.len == 5);
assert(sl.cap == 8);
};
@test fn dotfld_pseudo_len_stareq() void = {
let buf: [8]u8 = [1u8,2u8,3u8,4u8,5u8,6u8,7u8,8u8];
let sl: []u8 = buf[0:4];
sl.len *= 3;
assert(sl.len == 12);
assert(sl.cap == 8);
};
@test fn dotfld_plain_assign_ctrl() void = {
let s: Sii = Sii{f=1, g=0};
s.f = 99;
assert(s.f == 99);
assert(s.g == 0);
};