// Project #83: the general N-ary tuple- // destructure per-element register-return. The send (N_RETURN) and receive // (N_MLET / N_MASSIGN) sites previously gated the 3-word {ptr,len,cap} store // on a str-only XOR (e0_is_str ^ e1_is_str), which admitted EXACTLY ONE str // element and was slice-BLIND: a tuple with a []u8 element fell to the // scalar-pair fallback and silently DROPPED len+cap (only .ptr landed). The // fix REPLACES the XOR with a positional per-element cursor (harec // create_unpack_bindings, ref/harec/src/check.c:1354-1416): each element rides // consecutive eightbytes over [AX,DX,CX,R8]; a slice/str rides its 3-word // header, a scalar rides 1. SEND and RECEIVE walk the SAME cursor. // // Migrated from test/wcc/945_tuple_nary_destructure_run.c. Every wide row has // cap!=len so a dropped len OR cap is caught; N_MASSIGN rows pre-poison the // destination slot (distinct len/cap via a proven 3-word let-init copy) so a // dropped len/cap reads the poison, never the test value. Each []u8 element // borrows a str literal's .ptr (stable .rodata). Row F (slice_slice_recv) is // the over-cap 6-eightbyte tuple that #10 Fold A sret's at the SEND and Fold B // copies out at the RECEIVE — a working round-trip. cstage run is test-lang; // cs==ww byte-id is test-lang-byteid (T2) — both dimensions survive. package tuple_nary_destructure_test; fn mk_mlet_islice() (i64, []u8) = { let b: str = "hi"; let p: []u8; p.ptr = b.ptr; p.len = 2; p.cap = 5; return (4i64, p); }; fn mk_massign_islice() (i64, []u8) = { let b: str = "hi"; let p: []u8; p.ptr = b.ptr; p.len = 2; p.cap = 5; return (4i64, p); }; fn mk_mlet_istr() (i64, str) = { let p: str = "hi"; p.cap = 7i32; return (4i64, p); }; fn mk_massign_istr() (i64, str) = { let p: str = "hi"; p.cap = 7i32; return (4i64, p); }; fn mk_str_control() str = { let p: str = "hello"; p.cap = 9i32; return p; }; fn mk_massign_blank_wide() ([]u8, i64) = { let b: str = "hi"; let p: []u8; p.ptr = b.ptr; p.len = 2; p.cap = 5; return (p, 7i64); }; fn mk_slice_slice_recv() ([]u8, []u8) = { let a: []u8; a.len = 1; a.cap = 5; let b: []u8; b.len = 2; b.cap = 6; return (a, b); }; @test fn mlet_islice() void = { let (a, s) = mk_mlet_islice(); assert(a == 4); assert(s.len: i32 == 2); assert(s.cap: i32 == 5); assert(s[0] == 104u8); }; @test fn massign_islice() void = { let qb: str = "zzzz"; let q: []u8; q.ptr = qb.ptr; q.len = 9; q.cap = 9; let a: i64 = 0i64; let s: []u8 = q; a, s = mk_massign_islice(); assert(a == 4); assert(s.len: i32 == 2); assert(s.cap: i32 == 5); assert(s[0] == 104u8); }; @test fn mlet_istr() void = { let (a, s) = mk_mlet_istr(); assert(a == 4); assert(s.len: i32 == 2); assert(s.cap: i32 == 7); assert(s[0] == 104u8); }; @test fn massign_istr() void = { let q: str = "qqqq"; q.cap = 6i32; let a: i64 = 0i64; let s: str = q; a, s = mk_massign_istr(); assert(a == 4); assert(s.len: i32 == 2); assert(s.cap: i32 == 7); assert(s[0] == 104u8); }; @test fn str_control() void = { let s: str = mk_str_control(); assert(s.len: i32 == 5); assert(s.cap: i32 == 9); assert(s[0] == 104u8); }; @test fn massign_blank_wide() void = { let a: i64 = 0i64; _, a = mk_massign_blank_wide(); assert(a == 7); }; @test fn slice_slice_recv() void = { let (x, y) = mk_slice_slice_recv(); assert(x.len: i32 == 1); assert(x.cap: i32 == 5); assert(y.len: i32 == 2); assert(y.cap: i32 == 6); };