test: migrate struct/sret round-trip family-7 to test/lang @test, retire C twins (fold-2)

Continue fold-2: migrate the struct-by-value / sret round-trip family from
bespoke build+run C twins to test/lang @test, retiring each twin in the same
commit. Runtime coverage MOVES from $(TESTS) to test-lang (T1 runs+asserts via
`ww test`) + test-lang-byteid (T2 keeps cs==ww .s byte-id); the $(TESTS)
headline drops 6. Every assert is a primitive int/u8/bool comparison (no
fmt/strconv in the assert path); each returned struct/tuple FIELD is asserted
individually so a dropped/mis-offset/over-wide word FAILS. 46 @test cases, a
strict superset of the 46 C rows (799=4, 925=10, 930=6, 949odd=7, 949chained=9,
949aggret=10).

  799_tuple_sret_receive_run.c   -> tuple_sret_receive_test.ww    (#10 Fold B: over-4-GP tuple `([]u8,[]u8)` sret RECEIVE — destructure/single-var/return-forward/reassign; len() only on destructured bindings, never len(t.N))
  925_sret_struct_return_run.c   -> sret_struct_return_test.ww     (#23: >24B sret round-trip; 32B/40B/nested/slice-payload, reassign-receive, struct16-by-value-arg #11 collision, N_IDENT return rhs, forward #9 simple/multi-arg/slice)
  930_sret_narrow_field_run.c    -> sret_narrow_field_test.ww      (#33: sret narrow trailing-field copy — bool/u8/i16/i32 + mixed bool+i32+i64 after the 24B slice)
  949_oddstruct_byval_ret_run.c  -> oddstruct_byval_ret_test.ww    (#107: by-value return of odd sub-8 size {3,5,6,7} single-eightbyte + 8/12/24 boundaries)
  949_chained_dot_struct_copy_run.c -> chained_dot_struct_copy_test.ww (#107 sibling: chained-DOT `t.m.l = s` natural-size tail copy {0..7} + via-CX global dest; neighbour z is the oracle)
  949_aggret_source_run.c        -> aggret_source_test.ww          (#272: aggregate return from every addressable source — arrlit/N_DOT/N_INDEX/deref/ident + >24B sret arm + global-receive caller-half)

This family is sret / struct-by-value-return (the #107/#38/#271/#272 ABI area):
all 6 new files are byte-id cs==ww (no fold-5 divergence surfaced). Bump
LANGBYTEID_EXPECTED_MIN 43->49 to ratchet the new corpus floor.
This commit is contained in:
2026-06-22 13:52:41 +09:00
parent c9c5f6406f
commit d8e7470555
13 changed files with 611 additions and 1685 deletions

View File

@@ -0,0 +1,105 @@
// aggret_source_test — aggregate return-by-value from every ADDRESSABLE source
// shape (#272), migrated from test/wcc/949_aggret_source_run.c. The N_RETURN
// aggregate arms gated the source on N_IDENT || N_STRUCTLIT; every OTHER
// aggregate rvalue (array literal, struct/array field N_DOT, array element
// N_INDEX, deref *p) fell to the scalar-AX default = a silent truncation to the
// first 8 bytes, and both stages emitted byte-IDENTICAL wrong asm (#263 pure
// form — byte-id alone could NOT catch it). Each @test asserts every returned
// member as a primitive (a dropped word fails); T2 keeps the cs==ww net. Also
// covers the #272 commit-2 caller-half: receive into a GLOBAL ≤24B / >24B array.
package aggret_source_test;
type box_da = struct { a: [3]i64 };
type pair_sd = struct { a: i64, b: i64 };
type box_sd = struct { p: pair_sd };
type pair_sr = struct { a: i64, b: i64 };
let g2_idx: [2][3]i64 = [[1i64,2i64,3i64],[4i64,5i64,6i64]];
let g_recv: [3]i64 = [0i64, 0i64, 0i64];
let g_recv4: [4]i64 = [0i64,0i64,0i64,0i64];
fn mk_arrlit() [3]i64 = { return [1i64, 2i64, 3i64]; };
fn mk_da() [3]i64 = { let o: box_da = box_da { a = [10i64, 20i64, 30i64] }; return o.a; };
fn mk_idx() [3]i64 = { return g2_idx[1]; };
fn mk_deref(p: *[3]i64) [3]i64 = { return *p; };
fn mk_ident() [3]i64 = { let a: [3]i64 = [2i64, 4i64, 6i64]; return a; };
fn mk_deref4(p: *[4]i64) [4]i64 = { return *p; };
fn mk_sd() pair_sd = { let bx: box_sd = box_sd { p = pair_sd { a = 3i64, b = 4i64 } }; return bx.p; };
fn mk_sr(p: *pair_sr) pair_sr = { return *p; };
fn mk_grecv() [3]i64 = { return [4i64, 5i64, 6i64]; };
fn mk_grecv4(p: *[4]i64) [4]i64 = { return *p; };
@test fn arrlit() void = {
let r: [3]i64 = mk_arrlit();
assert(r[0] == 1i64);
assert(r[1] == 2i64);
assert(r[2] == 3i64);
};
@test fn dot_arrfield() void = {
let r: [3]i64 = mk_da();
assert(r[0] == 10i64);
assert(r[1] == 20i64);
assert(r[2] == 30i64);
};
@test fn index_elem() void = {
let r: [3]i64 = mk_idx();
assert(r[0] == 4i64);
assert(r[1] == 5i64);
assert(r[2] == 6i64);
};
@test fn deref() void = {
let a: [3]i64 = [7i64, 8i64, 9i64];
let r: [3]i64 = mk_deref(&a);
assert(r[0] == 7i64);
assert(r[1] == 8i64);
assert(r[2] == 9i64);
};
@test fn ident_ctl() void = {
let r: [3]i64 = mk_ident();
assert(r[0] == 2i64);
assert(r[1] == 4i64);
assert(r[2] == 6i64);
};
@test fn deref_sret() void = {
let a: [4]i64 = [1i64, 2i64, 3i64, 4i64];
let r: [4]i64 = mk_deref4(&a);
assert(r[0] == 1i64);
assert(r[1] == 2i64);
assert(r[2] == 3i64);
assert(r[3] == 4i64);
};
@test fn struct_dot() void = {
let r: pair_sd = mk_sd();
assert(r.a == 3i64);
assert(r.b == 4i64);
};
@test fn struct_deref() void = {
let x: pair_sr = pair_sr { a = 5i64, b = 9i64 };
let r: pair_sr = mk_sr(&x);
assert(r.a == 5i64);
assert(r.b == 9i64);
};
@test fn global_recv() void = {
g_recv = mk_grecv();
assert(g_recv[0] == 4i64);
assert(g_recv[1] == 5i64);
assert(g_recv[2] == 6i64);
};
@test fn global_recv_sret() void = {
let a: [4]i64 = [4i64, 5i64, 6i64, 7i64];
g_recv4 = mk_grecv4(&a);
assert(g_recv4[0] == 4i64);
assert(g_recv4[1] == 5i64);
assert(g_recv4[2] == 6i64);
assert(g_recv4[3] == 7i64);
};

View File

@@ -0,0 +1,113 @@
// chained_dot_struct_copy_test — depth-≥2 chained-DOT struct-field store from a
// struct IDENT source (`t.m.l = s;`, lhs.lhs is itself an N_DOT), migrated from
// test/wcc/949_chained_dot_struct_copy_run.c (#107-class sibling). The copy
// length is the field's NATURAL (non-slot-padded) struct size; cstage's tail
// selector handled only {4,1} and over-MOVQ'd every other tail {2,3,5,6,7},
// clobbering the @packed neighbour `z` that follows the field within 8 bytes —
// silently, and divergent from wwstage's descending 8/4/2/1 ladder. The fix
// aligns cstage UP. The oracle is the neighbour `z` read back AFTER the copy
// (a wrong width over-writes it); T2 keeps the cs==ww net. Coverage = the tail
// widths the bug lived in {2,3,5,6,7} plus boundaries {0,1,4} + the via-CX
// (global dest) arm a BP-local `t` never reaches.
package chained_dot_struct_copy_test;
type L2 = struct { a: u16, b: [8]u8 };
type M2 = struct @packed { l: L2, z: u8 };
type T2 = struct { m: M2, tail: u64 };
type L3 = struct @packed { a: u8, b: u8, c: u8 };
type M3 = struct @packed { l: L3, z: u8 };
type T3 = struct { m: M3, tail: u64 };
type L4 = struct @packed { a: u32 };
type M4 = struct @packed { l: L4, z: u8 };
type T4 = struct { m: M4, tail: u64 };
type L5 = struct @packed { a: u8, b: u32 };
type M5 = struct @packed { l: L5, z: u8 };
type T5 = struct { m: M5, tail: u64 };
type L6 = struct @packed { a: u16, b: u32 };
type M6 = struct @packed { l: L6, z: u8 };
type T6 = struct { m: M6, tail: u64 };
type L7 = struct @packed { a: u8, b: u16, c: u32 };
type M7 = struct @packed { l: L7, z: u8 };
type T7 = struct { m: M7, tail: u64 };
type Lg = struct { a: u16, b: [8]u8 };
type Mg = struct @packed { l: Lg, z: u8 };
type Tg = struct { m: Mg, tail: u64 };
type L1 = struct @packed { a: u8 };
type M1 = struct @packed { l: L1, z: u8 };
type T1 = struct { m: M1, tail: u64 };
type L0 = struct { a: i64, b: i64 };
type M0 = struct { l: L0, z: u8 };
type T0 = struct { m: M0, tail: u64 };
let g_viacx: Tg = Tg { m = Mg { l = Lg { a = 0u16, b = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8] }, z = 222u8 }, tail = 0u64 };
@test fn tail2_leaf10() void = {
let s = L2 { a = 0u16, b = [9u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8] };
let t = T2 { m = M2 { l = L2 { a = 0u16, b = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8] }, z = 222u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 222);
};
@test fn tail3_leaf3() void = {
let s = L3 { a = 1u8, b = 2u8, c = 3u8 };
let t = T3 { m = M3 { l = L3 { a = 0u8, b = 0u8, c = 0u8 }, z = 88u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 88);
};
@test fn tail4_leaf4() void = {
let s = L4 { a = 7u32 };
let t = T4 { m = M4 { l = L4 { a = 0u32 }, z = 123u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 123);
};
@test fn tail5_leaf5() void = {
let s = L5 { a = 1u8, b = 0u32 };
let t = T5 { m = M5 { l = L5 { a = 0u8, b = 0u32 }, z = 177u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 177);
};
@test fn tail6_leaf6() void = {
let s = L6 { a = 1u16, b = 0u32 };
let t = T6 { m = M6 { l = L6 { a = 0u16, b = 0u32 }, z = 99u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 99);
};
@test fn tail7_leaf7() void = {
let s = L7 { a = 1u8, b = 2u16, c = 0u32 };
let t = T7 { m = M7 { l = L7 { a = 0u8, b = 0u16, c = 0u32 }, z = 111u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 111);
};
@test fn viacx_global_tail2() void = {
let s = Lg { a = 0u16, b = [9u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8] };
g_viacx.m.l = s;
assert(g_viacx.m.z: i32 == 222);
};
@test fn tail1_leaf1() void = {
let s = L1 { a = 5u8 };
let t = T1 { m = M1 { l = L1 { a = 0u8 }, z = 144u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 144);
};
@test fn tail0_leaf16() void = {
let s = L0 { a = 5i64, b = 6i64 };
let t = T0 { m = M0 { l = L0 { a = 0i64, b = 0i64 }, z = 200u8 }, tail = 0u64 };
t.m.l = s;
assert(t.m.z: i32 == 200);
};

View File

@@ -0,0 +1,75 @@
// oddstruct_byval_ret_test — by-value RETURN of a struct whose total size is an
// "odd" sub-8 width {3,5,6,7} (a single INTEGER eightbyte in RAX), migrated from
// test/wcc/949_oddstruct_byval_ret_run.c (#107). Pre-#107 cstage's N_LET receive
// fell past every arm for these sizes and SILENTLY DROPPED the CALL (exit 0,
// reading an uninit slot); wwstage's generic fallback emitted a single MOVQ, so
// it was both a silent miscompile AND a gate-blind cs≠ww divergence. The #107
// fix mirrors wwstage's single-MOVQ receive. Each @test reads back the planted
// fields as primitives (the whole eightbyte must reach the caller, not just AX's
// low byte); T2 keeps the cs==ww net. Sizes 8/12/24 lock the existing
// sized-tail / multi-word receive paths were not perturbed.
package oddstruct_byval_ret_test;
type T3 = struct { a: u8, b: u8, c: u8 };
type T5 = struct @packed { a: u8, b: u32 };
type T6 = struct { a: u16, b: u16, c: u16 };
type T7 = struct @packed { a: u8, b: u16, c: u32 };
type T8 = struct { a: i32, b: i32 };
type T12 = struct { a: i32, b: i32, c: i32 };
type T24 = struct { a: i64, b: i64, c: i64 };
fn mk3() T3 = { return T3 { a = 116u8, b = 22u8, c = 33u8 }; };
fn mk5() T5 = { return T5 { a = 9u8, b = 116u32 }; };
fn mk6() T6 = { return T6 { a = 9u16, b = 22u16, c = 116u16 }; };
fn mk7() T7 = { return T7 { a = 9u8, b = 22u16, c = 116u32 }; };
fn mk8() T8 = { return T8 { a = 116, b = 22 }; };
fn mk12() T12 = { return T12 { a = 9, b = 22, c = 116 }; };
fn mk24() T24 = { return T24 { a = 9i64, b = 22i64, c = 116i64 }; };
@test fn s3_u8x3_fieldA() void = {
let r: T3 = mk3();
assert(r.a: i32 == 116);
assert(r.b: i32 == 22);
assert(r.c: i32 == 33);
};
@test fn s5_packed_fieldB() void = {
let r: T5 = mk5();
assert(r.a: i32 == 9);
assert(r.b: i32 == 116);
};
@test fn s6_u16x3_fieldC() void = {
let r: T6 = mk6();
assert(r.a: i32 == 9);
assert(r.b: i32 == 22);
assert(r.c: i32 == 116);
};
@test fn s7_packed_fieldC() void = {
let r: T7 = mk7();
assert(r.a: i32 == 9);
assert(r.b: i32 == 22);
assert(r.c: i32 == 116);
};
@test fn s8_i32x2_fieldA() void = {
let r: T8 = mk8();
assert(r.a == 116);
assert(r.b == 22);
};
@test fn s12_i32x3_fieldC() void = {
let r: T12 = mk12();
assert(r.a == 9);
assert(r.b == 22);
assert(r.c == 116);
};
@test fn s24_i64x3_fieldC() void = {
let r: T24 = mk24();
assert(r.a == 9i64);
assert(r.b == 22i64);
assert(r.c == 116i64);
};

View File

@@ -0,0 +1,81 @@
// sret_narrow_field_test — sret callee's narrow trailing-field copy (#33),
// migrated from test/wcc/930_sret_narrow_field_run.c. A >24B struct that ends in
// a narrow primitive (bool / u8 / i16 / i32) must copy exactly that field's
// width; pre-fix cstage's N_IDENT word-copy tail used a slot-padded MOVQ that
// swept the bordering @sretarg save byte into the trailing field. Each @test
// asserts the trailing field round-trips as a primitive; T2 keeps the cs==ww net.
// The mixed row interleaves bool + i32 + i64 after the 24B slice payload so each
// trailing field must emit its declared width at its natural offset.
package sret_narrow_field_test;
type tbool = struct { a: i32, s: []u8, r: bool };
type tu8 = struct { a: i32, s: []u8, r: u8 };
type ti16 = struct { a: i32, s: []u8, r: i16 };
type ti32 = struct { a: i32, s: []u8, r: i32 };
type tmix = struct { s: []u8, r: bool, n: i32, k: i64 };
fn mk_bt() tbool = {
let v: tbool; let z: []u8;
v.s = z; v.a = 7; v.r = true;
return v;
};
fn mk_bf() tbool = {
let v: tbool; let z: []u8;
v.s = z; v.a = 9; v.r = false;
return v;
};
fn mk_u8() tu8 = {
let v: tu8; let z: []u8;
v.s = z; v.a = 0; v.r = 0xFFu8;
return v;
};
fn mk_i16() ti16 = {
let v: ti16; let z: []u8;
v.s = z; v.a = 0; v.r = -123i16;
return v;
};
fn mk_i32() ti32 = {
let v: ti32; let z: []u8;
v.s = z; v.a = 0; v.r = -424242;
return v;
};
fn mk_mix() tmix = {
let v: tmix; let z: []u8;
v.s = z; v.r = true; v.n = 1234567; v.k = 9876543210i64;
return v;
};
@test fn bool_true() void = {
let x: tbool = mk_bt();
assert(x.a == 7);
assert(x.r);
};
@test fn bool_false() void = {
let x: tbool = mk_bf();
assert(x.a == 9);
assert(!x.r);
};
@test fn u8_high_bit() void = {
let x: tu8 = mk_u8();
assert(x.r == 0xFFu8);
};
@test fn i16_negative() void = {
let x: ti16 = mk_i16();
assert(x.r == -123i16);
};
@test fn i32_negative() void = {
let x: ti32 = mk_i32();
assert(x.r == -424242);
};
@test fn mixed_narrow_after_slice() void = {
let x: tmix = mk_mix();
assert(x.r);
assert(x.n == 1234567);
assert(x.k == 9876543210i64);
};

View File

@@ -0,0 +1,176 @@
// sret_struct_return_test — System V AMD64 sret (>24B struct return) end-to-end
// round-trip, migrated from test/wcc/925_sret_struct_return_run.c (#23). Values
// must cross the >24B struct-return boundary intact; pre-#23 both stages were
// broken differently (cstage skipped the CALL emit, wwstage truncated to AX), so
// asm byte-id was blind. Each @test asserts every returned field as a primitive,
// and T2 (test-lang-byteid) keeps the cs==ww net the .c twin's dual-driver gave.
// Coverage: 32B/40B/nested/slice-payload shapes, reassign-receive, the
// struct16-by-value-arg collision (#11 sister), N_IDENT return rhs, and the
// return-forwarding path (#9) for simple / multi-arg / slice-payload shapes.
package sret_struct_return_test;
type quad = struct { a: i64, b: i64, c: i64, d: i64 };
type five = struct { a: i64, b: i64, c: i64, d: i64, e: i64 };
type decoder = struct { offs: i64, src: []u8 };
type pair = struct { x: i64, y: i64 };
type inner = struct { p: i64, q: i64 };
type outer = struct { i: inner, s: i64, t: i64 };
type pos = struct { x: i64, y: i64, z: i64, w: i64 };
fn mk_quad(x: i64) quad = {
return quad { a = x, b = x + 1i64, c = x + 2i64, d = x + 3i64 };
};
fn mk_dec(s: []u8) decoder = {
let r: decoder;
r.offs = 42i64;
r.src = s;
return r;
};
fn mk_five() five = {
return five { a = 1i64, b = 2i64, c = 3i64, d = 4i64, e = 5i64 };
};
fn mk_outer() outer = {
return outer {
i = inner { p = 100i64, q = 200i64 },
s = 300i64, t = 400i64
};
};
fn mk_quad_s(s: i64) quad = {
return quad { a = s, b = s, c = s, d = s };
};
fn mk_quad_pair(p: pair, k: i64) quad = {
return quad { a = p.x, b = p.y, c = k, d = p.x + p.y + k };
};
fn mk_pos() pos = {
let r: pos;
r.x = 11i64;
r.y = 22i64;
r.z = 33i64;
r.w = 44i64;
return r;
};
fn fwd_inner(x: i64) quad = {
return quad { a = x, b = x + 1i64, c = x + 2i64, d = x + 3i64 };
};
fn fwd_outer(x: i64) quad = {
return fwd_inner(x);
};
fn fwd2_inner(p: pair, k: i64) quad = {
return quad { a = p.x, b = p.y, c = k, d = p.x + p.y + k };
};
fn fwd2_outer(p: pair, k: i64) quad = {
return fwd2_inner(p, k);
};
fn fwddec_inner(s: []u8) decoder = {
let r: decoder;
r.offs = 99i64;
r.src = s;
return r;
};
fn fwddec_outer(s: []u8) decoder = {
return fwddec_inner(s);
};
@test fn quad_i64_roundtrip() void = {
let q: quad = mk_quad(10i64);
assert(q.a == 10i64);
assert(q.b == 11i64);
assert(q.c == 12i64);
assert(q.d == 13i64);
};
@test fn decoder_slice_payload() void = {
let buf: [3]u8;
buf[0] = 0xa1u8;
buf[1] = 0xb2u8;
buf[2] = 0xc3u8;
let d: decoder = mk_dec(buf[0:3]);
assert(d.offs == 42i64);
assert(d.src.len == 3);
assert(d.src[0] == 0xa1u8);
assert(d.src[1] == 0xb2u8);
assert(d.src[2] == 0xc3u8);
};
@test fn five_i64_roundtrip() void = {
let f: five = mk_five();
assert(f.a == 1i64);
assert(f.b == 2i64);
assert(f.c == 3i64);
assert(f.d == 4i64);
assert(f.e == 5i64);
};
@test fn nested_struct_payload() void = {
let o: outer = mk_outer();
assert(o.i.p == 100i64);
assert(o.i.q == 200i64);
assert(o.s == 300i64);
assert(o.t == 400i64);
};
@test fn reassign_receive() void = {
let q: quad;
q = mk_quad_s(7i64);
assert(q.a == 7i64);
assert(q.b == 7i64);
assert(q.c == 7i64);
assert(q.d == 7i64);
};
@test fn sret_with_struct16_arg() void = {
let p: pair = pair { x = 3i64, y = 5i64 };
let q: quad = mk_quad_pair(p, 11i64);
assert(q.a == 3i64);
assert(q.b == 5i64);
assert(q.c == 11i64);
assert(q.d == 19i64);
};
@test fn ident_return_rhs() void = {
let p: pos = mk_pos();
assert(p.x == 11i64);
assert(p.y == 22i64);
assert(p.z == 33i64);
assert(p.w == 44i64);
};
@test fn forward_simple() void = {
let q: quad = fwd_outer(10i64);
assert(q.a == 10i64);
assert(q.b == 11i64);
assert(q.c == 12i64);
assert(q.d == 13i64);
};
@test fn forward_multi_arg() void = {
let p: pair = pair { x = 4i64, y = 6i64 };
let q: quad = fwd2_outer(p, 9i64);
assert(q.a == 4i64);
assert(q.b == 6i64);
assert(q.c == 9i64);
assert(q.d == 19i64);
};
@test fn forward_slice_payload() void = {
let buf: [3]u8;
buf[0] = 0x11u8;
buf[1] = 0x22u8;
buf[2] = 0x33u8;
let d: decoder = fwddec_outer(buf[0:3]);
assert(d.offs == 99i64);
assert(d.src.len == 3);
assert(d.src[0] == 0x11u8);
assert(d.src[1] == 0x22u8);
assert(d.src[2] == 0x33u8);
};

View File

@@ -0,0 +1,60 @@
// tuple_sret_receive_test — wide tuple-return / sret RECEIVE side (#10 Fold B),
// migrated from test/wcc/799_tuple_sret_receive_run.c. A fn returning a tuple
// over the 4-GP cap (`([]u8, []u8)` = 6 GP eightbytes) sret's into the caller's
// dest; each receive form must lay the elements out at the SAME packed offset
// the SEND wrote. byte-id alone is blind to a receive that mis-offsets (both
// stages would be wrong the same way), so each @test RUNS the round-trip and
// asserts the bytes arrive intact; T2 (test-lang-byteid) keeps the cs==ww net.
//
// Data is read back by INDEXING the slice elements (t.0[i] / a[i]); len() is
// taken only on DESTRUCTURED bindings (plain slice locals), never `len(t.N)` —
// that is a SEPARATE N_DOT-tuple+len composition bug, deliberately not exercised.
package tuple_sret_receive_test;
fn mk(a: []u8, b: []u8) ([]u8, []u8) = { return (a, b); };
fn fwd(a: []u8, b: []u8) ([]u8, []u8) = { return mk(a, b); };
@test fn destructure() void = {
let buf: [8]u8 = [10u8, 11u8, 12u8, 13u8, 20u8, 21u8, 22u8, 23u8];
let x: []u8 = buf[0:4];
let y: []u8 = buf[4:8];
let (a, b) = mk(x, y);
assert(len(a) == 4);
assert(len(b) == 4);
assert(a[0] == 10u8);
assert(a[3] == 13u8);
assert(b[0] == 20u8);
assert(b[3] == 23u8);
};
@test fn single_var_let() void = {
let buf: [8]u8 = [10u8, 11u8, 12u8, 13u8, 20u8, 21u8, 22u8, 23u8];
let x: []u8 = buf[0:4];
let y: []u8 = buf[4:8];
let t = mk(x, y);
assert(t.0[0] == 10u8);
assert(t.0[3] == 13u8);
assert(t.1[0] == 20u8);
assert(t.1[3] == 23u8);
};
@test fn return_forward() void = {
let buf: [8]u8 = [10u8, 11u8, 12u8, 13u8, 20u8, 21u8, 22u8, 23u8];
let x: []u8 = buf[0:4];
let y: []u8 = buf[4:8];
let (a, b) = fwd(x, y);
assert(len(a) == 4);
assert(a[0] == 10u8);
assert(b[3] == 23u8);
};
@test fn reassign() void = {
let buf: [8]u8 = [10u8, 11u8, 12u8, 13u8, 20u8, 21u8, 22u8, 23u8];
let x: []u8 = buf[0:4];
let y: []u8 = buf[4:8];
let t = mk(x, y);
t = mk(y, x);
assert(t.0[0] == 20u8);
assert(t.1[0] == 10u8);
};