// subslice_ptresz_test — a sub-slice `base[lo:hi]` must advance its DATA // pointer by lo*esz (BYTES), not by lo (element COUNT), migrated from // test/wcc/943_subslice_ptresz_run.c (project #76). The rt invariant is // membsz-unit pointer arithmetic (ref/hare/rt/ensure.ha:30). For esz==1 (u8/str) // lo*1 == lo, so those paths are unaffected; the bug only bites esz>1. // // Before the fix BOTH stages emitted ptr = base + lo (unscaled), so the first // element was read at byte offset `lo` into the base — garbage straddling // base[0]/base[1] for any esz>1. Each row picks values where the unscaled read // cannot alias the scaled one, so a stale `+lo` stage returns garbage, not the // expected element. Exercises esz 2/4/8 over array + slice bases via the // let-form (value path) and the call-arg fast path. package subslice_ptresz_test; fn e0(s: []i32) i32 = { return s[0]; }; fn e1(s: []i32) i32 = { return s[1]; }; fn f0(s: []i64) i64 = { return s[0]; }; fn f1(s: []i64) i64 = { return s[1]; }; @test fn subslice_esz4_array_let() void = { // A — esz=4 array base, let-form (value path). s[0]=a[2]=1002. let a: [8]i32; let i: i32 = 0; for (i < 8) { a[i] = 1000 + i; i += 1; }; let s: []i32 = a[2:5]; assert(s.len: i32 == 3); assert(s[0] == 1002); assert(s[1] == 1003); }; @test fn subslice_esz2_array_let() void = { // B — esz=2 array base, let-form. s[0]=a[3]=103. let a: [8]i16; let i: i32 = 0; for (i < 8) { a[i] = (100 + i): i16; i += 1; }; let s: []i16 = a[3:6]; assert(s.len: i32 == 3); assert(s[0]: i32 == 103); assert(s[1]: i32 == 104); }; @test fn subslice_esz8_array_let() void = { // C — esz=8 array base, let-form. s[0]=a[1]=5001. let a: [8]i64; let i: i32 = 0; for (i < 8) { a[i] = (5000 + i): i64; i += 1; }; let s: []i64 = a[1:4]; assert(s.len: i32 == 3); assert(s[0]: i32 == 5001); assert(s[1]: i32 == 5002); }; @test fn subslice_esz4_slice_let() void = { // D — esz=4 slice base, let-form. base ptr from header + lo*esz. // s[0]=a[2]=1002. let a: [8]i32; let i: i32 = 0; for (i < 8) { a[i] = 1000 + i; i += 1; }; let p: []i32; p.ptr = &a[0]; p.len = 6; p.cap = 8; let s: []i32 = p[2:5]; assert(s.len: i32 == 3); assert(s[0] == 1002); assert(s[1] == 1003); }; @test fn subslice_esz4_call_arg() void = { // E — esz=4 call-arg (the pushargsrev twin). The fn reads s[0]/s[1] of // `a[3:6]` -> 1003 / 1004. let a: [8]i32; let i: i32 = 0; for (i < 8) { a[i] = 1000 + i; i += 1; }; assert(e0(a[3:6]) == 1003); assert(e1(a[3:6]) == 1004); }; @test fn subslice_esz8_call_arg() void = { // F — esz=8 call-arg. The fns read s[0]/s[1] of `a[2:5]` -> 5002 / 5003. let a: [8]i64; let i: i32 = 0; for (i < 8) { a[i] = (5000 + i): i64; i += 1; }; assert(f0(a[2:5]): i32 == 5002); assert(f1(a[2:5]): i32 == 5003); };