// f6_header_test — 24B str/slice header partial load/store; .cap/.len read back // after a clobber, migrated from test/wcc/949_f6_header_run.c. Three closed // sub-bugs, all cs==ww-blind at the byte-id gates so a behavioral @test is the // net: // #19 (align-UP, wwstage-only): a str->[]u8 cast from a NON-LOCAL source // (global ident / struct field / call result) missed the cap=len synth, // leaving CX = the str's stale word-16 garbage cap. // #28 (#263 both-stages): a tuple slice-element read `t.N` over a ([]u8,i64) // loaded only the ptr word — a SLICE element fell to the scalar tail, so // len/cap took stale registers across a clobber() call. // #29 (#263 both-stages): a chained-dot str leaf `o.i.s` (depth-2) dropped the // cap word, so a junk strlit before the chain left CX stale. // All asserted post-fix both-stages-CORRECT; the runtime read-back with DISTINCT // values (cap=3/5, len=5/6) is the net a byte-id gate alone was blind to. package f6_header_test; let g_abc: str = "abc"; type box = struct { s: str, x: i64 }; type innerc = struct { s: str, x: i64 }; type outerc = struct { i: innerc, y: i64 }; type innero = struct { pad: i64, s: str }; type outero = struct { i: innero, y: i64 }; fn castg() []u8 = { return g_abc: []u8; }; fn clobber() i64 = { let a: i64 = 111; let b: i64 = 222; return a + b; }; @test fn global_str_cap() void = { // #19: str->[]u8 cast from a GLOBAL ident source, threaded through a call // return. cap must == len == 3. Pre-fix wwstage left CX = stale word-16. let s: []u8 = castg(); assert(s.cap: i32 == 3); }; @test fn field_str_cap() void = { // #19 sibling: str->[]u8 cast from a struct FIELD source; distinct len (5) // catches a dropped cap. let b: box = box { s = "hello", x = 0 }; let v: []u8 = b.s: []u8; assert(v.cap: i32 == 5); }; @test fn local_str_cap() void = { // #19 control: LOCAL str source (the pre-fix-covered shape) still emits the // synth — guards the common case against regression. let s: str = "abcd"; let v: []u8 = s: []u8; assert(v.cap: i32 == 4); }; @test fn tuple_slice_elem() void = { // #28: tuple slice-element read `t.0` over a ([]u8, i64). A clobber() // between the build and the read leaves junk in BX/CX; pre-fix the // str-only arm fell to the scalar tail (ptr word only), so ys.len read // stale BX. len == 5. let xs: []u8 = [1u8, 2u8, 3u8, 4u8, 5u8]; let t: ([]u8, i64) = (xs, 7); let junk: i64 = clobber(); let ys: []u8 = t.0; assert(ys.len: i32 == 5); assert(junk == 333); }; @test fn tuple_slice_elem_pos1() void = { // #28 sibling: the slice element sits at tuple position 1 (an i64 occupies // slot 0, the []u8 header starts at +8). Exercises the widened arm's offset // arithmetic. len == 6. let xs: []u8 = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]; let t: (i64, []u8) = (9, xs); let junk: i64 = clobber(); let ys: []u8 = t.1; assert(ys.len: i32 == 6); assert(junk == 333); }; @test fn chained_str_cap() void = { // #29: chained-dot str leaf `o.i.s` (depth-2) dropped the cap word — a junk // strlit before the chain left CX stale, so t.cap read 2 (junk's cap) // instead of 5. Now the str leaf loads all three header words. let iv: innerc = innerc { s = "hello", x = 0 }; let o: outerc = outerc { i = iv, y = 0 }; let junk: str = "ab"; let t: str = o.i.s; assert(t.cap: i32 == 5); }; @test fn chained_str_cap_offset() void = { // #29 sibling: the str leaf sits at a NON-ZERO field offset (a leading i64 // pad pushes `s` to +8). Exercises the chained-leaf offset arithmetic; // cap == len == 7. let iv: innero = innero { pad = 0, s = "worldly" }; let o: outero = outero { i = iv, y = 0 }; let junk: str = "ab"; let t: str = o.i.s; assert(t.cap: i32 == 7); };