// rvalue_tuple_destructure_test — project #241: materialise an RVALUE tuple // into the SysV register-return cursor before a destructure / let bind. // Migrated from test/wcc/945_rvalue_tuple_destructure_run.c. cgexpr could not // produce a tuple VALUE: a literal `(a, b)` fell to the MOVQ $0 default, a // tuple-typed IDENT loaded only word0, and a `?`/`!` unwrap of a tuple-in- // union payload lifted only word0 — so a destructure read GARBAGE past the // first element (cstage), and the un-typed binder aborted wwstage's checker // (asserttyped). A DANGEROUS gate-blind cs!=ww (the strconv blocker // `let (sign, u) = parseint(s, base)?`). The fix packs an N_TUPLE literal and a // tuple IDENT into the register-return cursor and shifts a `?`/`!` tuple // success payload down past the tag; both stages byte-identical (rule 10). // // The C driver ran each row on both stages + asserted cs==ww .s byte-id; here // the cstage run is test-lang and the byte-id is test-lang-byteid (T2), so both // dimensions survive. The never-taken error arms abort() via assert(false), the // migrated-test idiom for a diverging arm in a yield/destructure context (the C // original `return 9`). package rvalue_tuple_destructure_test; type myerr = !void; type invalid = !void; fn mk(x: u64, s: bool) ((bool, u64) | myerr) = { return (s, x); }; fn parseint(base: int) ((bool, u64) | invalid) = { let sg: bool = true; let n: u64 = 42u64; return (sg, n); }; fn stoi(base: int) (u64 | invalid) = { let (sign, u) = parseint(base)?; if (!sign) { return 0u64; }; return u; }; @test fn literal_destructure() void = { let (a, b) = (true, 11u64); assert(b == 11u64); assert(a); }; @test fn match_yield() void = { let (sg, u) = match (mk(6u64, true)) { case let t: (bool, u64) => yield t; case myerr => { assert(false); }; }; assert(u == 6u64); assert(sg); }; @test fn trycall_strconv() void = { match (stoi(10)) { case let v: u64 => { assert(v == 42u64); }; case invalid => { assert(false); }; }; };