// @test fixture: every test passes (exits without aborting). package data; import rt; // #3/B': check_empty_alloc_annotated calls alloc → rt_malloc. type point = struct { x: i32, y: i32 }; @test fn check_add() void = { let a: i32 = 2; let b: i32 = 3; let c: i32 = a + b; if (c != 5) { let _: i32 = 1 / 0; // abort via div-by-zero would also work }; }; @test fn check_match() void = { let r: (i32 | str) = 7; let v: i32 = match (r) { case let n: i32 => yield n; case let s: str => yield 0; }; if (v != 7) { let _: i32 = 1 / 0; }; }; // #227: compound assign (`-=`/`+=`) on a local field must // load-combine-store, not drop the op. Pre-fix wwstage stored the bare // rhs (p.x->4, p.y->5, view.len->1), so each mismatch aborts via 1/0. @test fn check_local_field_compound() void = { let p: point = point { x = 10i32, y = 3i32 }; p.x -= 4i32; p.y += 5i32; if (p.x != 6) { let _: i32 = 1 / 0; }; if (p.y != 8) { let _: i32 = 1 / 0; }; let view: str = "hello"; view.len -= 1; let n: i32 = view.len: i32; if (n != 4) { let _: i32 = 1 / 0; }; }; // #264: a match-bound binder used inside a `yield` arm of a match-AS- // EXPRESSION. Pre-fix the wwstage checker stamped the operand in-scope // during the N_MCASE arm walk, then RE-TYPED it out of the (popped) arm // scope while deriving the match's yield type (exprtype N_MATCH → // matchyieldtype). Out of scope the operand couldn't re-resolve, the // re-derive returned nil, and the N_UN/N_BIN/N_INDEX restamp arms // overwrote the good in-scope stamp with nil → asserttyped:un/bin/index // aborted (cstage accepted it). Root fix: matchyieldtype now READS the // cached operand tinfo at the post-walk call instead of re-deriving // (mirrors cstage match_yield_type reading body->lhs->type, check.c:121), // so no operand shape can be clobbered. These rows pin the whole operand // class by construction: deref (*p), bin (*p+1), slice-index (p[i]), and // deref-then-field ((*p).x). (The *[N]T ptr-to-array index variant is // blocked separately by #278's exhaustiveness false-reject, so it uses a // []i32 slice binder here.) @test fn check_match_ptr_deref() void = { let n: i32 = 42i32; let xi: (*i32 | void) = &n; let v: i32 = match (xi) { case let p: *i32 => yield *p; case void => yield -1i32; }; if (v != 42) { let _: i32 = 1 / 0; }; // N_BIN operand: `yield *p + 1`. let m: i32 = 9i32; let xb: (*i32 | void) = &m; let vb: i32 = match (xb) { case let p: *i32 => yield *p + 1i32; case void => yield -1i32; }; if (vb != 10) { let _: i32 = 1 / 0; }; // N_INDEX operand: `yield p[1]` over a []i32 binder. let arr: [3]i32 = [4i32, 5i32, 6i32]; let sl: []i32 = arr; let xs: ([]i32 | void) = sl; let vs: i32 = match (xs) { case let p: []i32 => yield p[1]; case void => yield -1i32; }; if (vs != 5) { let _: i32 = 1 / 0; }; let pt: point = point { x = 7i32, y = 9i32 }; let xp: (*point | void) = &pt; let w: i32 = match (xp) { case let p: *point => yield (*p).x; case void => yield -1i32; }; if (w != 7) { let _: i32 = 1 / 0; }; }; // #3/B': the let-annotation context path keeps `alloc([], n)` inferring // its element type for ANY T (u8 default + non-u8 #45 retype). The bare / // return / arg empty allocs that lost the silent u8 default are covered by // the negative test (test/wcc/729). Here we pin that annotated allocs of // both an 8-bit and a wide element still compile and index correctly. // alloc([], n) is Hare's len=0 / cap=n empty slice, so we write into the // cap-backed memory and read it back (ref/hare expects len 0, not n). @test fn check_empty_alloc_annotated() void = { let b: []u8 = alloc([], 8u64)!; b[0] = 7u8; b[3] = 9u8; if (b[0] != 7 || b[3] != 9) { let _: i32 = 1 / 0; }; let w: []i32 = alloc([], 4u64)!; w[2] = 5i32; if (w[2] != 5) { let _: i32 = 1 / 0; }; };