Files
ww/test/lang/composite_call_arg_test.ww
Hojun-Cho 83f5956df2 test: banner purge + WHY-only comment sweep (rule 8)
Every section banner dies (103 -> 0) across test/lang, the observer
suites, the C carriers, and the five comment-heavy corpus fixtures;
banner provenance (#N cites, carrier numbers, repair-cluster labels)
folded into headers or adjacent WHY comments. Narration deleted; row
provenance, ref cites, divergence pins, and layout contracts kept
(fwd-ref decl-order guards and bootstrap-gate corpus rationale
restored where the sweep over-cut). Comment-only proven: all 3742
wwbuild workdir .s byte-identical before/after; test-commit and
test-byteid (161 lang + 1399 data, 0 pinned-divergent) green.
2026-08-08 21:40:23 +09:00

123 lines
3.3 KiB
Plaintext

// A 3-reg composite (`[]u8` slice) CALL result passed
// inline as a composite arg to another call, migrated from
// test/wcc/927_composite_call_arg_run.c (#24, Class A wwstage cgen miscompile).
// Pre-fix wwstage emitted a single `PUSHQ AX` for a slice-returning CALL arg
// (losing .len/.cap) and under-popped the receiver's arg-regs by two words: the
// arg-shift collision corrupts every subsequent arg (the receiver reads the
// caller's spilled p.ptr as its own s.len). The fix gave `nodeisslice` an N_CALL
// arm (mirroring nodeisstr): both the push side (3-PUSH CX,BX,AX) and the pop
// side (extra=2) fire for slice-returning CALLs as args. Each @test KEEPS the
// `check(view(s))` call-arg-composite shape under test and asserts the receiver
// saw the right .len (a check fn returns 0 only when its internal .len checks
// pass, so the asserted 0 IS the value contract).
package composite_call_arg_test;
fn view(s: str) []u8 = {
let r: []u8;
r.ptr = s.ptr;
r.len = s.len;
r.cap = s.len;
return r;
};
fn passthrough(a: []u8) []u8 = { return a; };
fn check_a(a: []u8) i32 = {
if (a.len == 13) { return 0; };
return 11;
};
fn check2_b(a: []u8, b: []u8) i32 = {
if (a.len != 13) { return 11; };
if (b.len != 5) { return 12; };
return 0;
};
fn check2_c(a: []u8, b: []u8) i32 = {
if (a.len != 3) { return 11; };
if (b.len != 5) { return 12; };
return 0;
};
fn check3_d(k0: i32, a: []u8, k1: i32) i32 = {
if (k0 != 7) { return 11; };
if (a.len != 4) { return 12; };
if (k1 != 9) { return 13; };
return 0;
};
fn check_e(a: []u8) i32 = {
if (a.len == 6) { return 0; };
return 11;
};
fn use2_f(a: []u8, k: i32) i32 = {
if (a.len != 13) { return 11; };
if (k != 99) { return 12; };
return 0;
};
type oserror = !i32;
fn yield_ptr() (*u8 | oserror) = {
let p: *u8 = nil;
return p;
};
fn dispatch(v: (*u8 | oserror)) i32 = {
match (v) {
case let p: *u8 => return 7;
case let e: oserror => return e: i32;
};
return -99;
};
@test fn canonical_slice_call() void = {
// (a) canonical f(g()) with g returning []u8.
let s: str = "hello, world!";
assert(check_a(view(s)) == 0);
};
@test fn slice_call_then_letslice() void = {
// (b) f(g(), p) — strings.hasprefix shape: slice-CALL then a let-slice.
let s: str = "hello, world!";
let p: []u8;
p.ptr = s.ptr;
p.len = 5;
p.cap = 5;
assert(check2_b(view(s), p) == 0);
};
@test fn two_composite_calls_args() void = {
// (c) f(g(in1), g(in2)) — two composite CALLs; the stack must hold both
// 3-word headers before the 6-POP drain.
let s1: str = "foo";
let s2: str = "hello";
assert(check2_c(view(s1), view(s2)) == 0);
};
@test fn slice_call_middle_arg() void = {
// (d) f(k0, g(), k1) — slice-CALL in the middle of three args.
let s: str = "abcd";
assert(check3_d(7, view(s), 9) == 0);
};
@test fn nested_composite_calls() void = {
// (e) f(g(h(s))) — composite-in-composite nesting.
let s: str = "abcdef";
assert(check_e(passthrough(view(s))) == 0);
};
@test fn slice_call_then_scalar() void = {
// (f) f(g(), 99) — slice-CALL then a scalar (pop-count mix).
let s: str = "hello, world!";
assert(use2_f(view(s), 99) == 0);
};
@test fn tagged_call_regression() void = {
// (g) tagged-CALL alongside the slice path — confirms #21's natural-push
// arm composes with #24's.
assert(dispatch(yield_ptr()) == 7);
};