cmd/w6c/cgen+test: skip dead TRYPROP propret on same-shape ?

Per CLAUDE.md rule 10, align cstage down to wwstage — when every
variant in a `?` propagation maps to itself, the remap loop emits
zero JMPs and the propret label is dead. Lazy-allocate it so the
label-counter ID is only consumed when at least one JMP fires.

Smoke test selfhost/test/trypromote.ww exercises same-shape
(i64|nomem)→(i64|nomem) propagation; cstage and wwstage now emit
byte-identical asm for the TRYPROP region.
This commit is contained in:
2026-05-19 17:45:13 +09:00
parent 2b46abe7d1
commit 58e6d349a2
3 changed files with 64 additions and 2 deletions

View File

@@ -0,0 +1,54 @@
// selfhost/test/trypromote.ww — smoke for `?` propagation through a
// `!void`-shaped alias.
//
// Task #2 (ww-strings-redesign): proves cgen's TRYPROP tag-remap works
// for the exact pattern lib/errors + os.alloc are about to lean on. We
// cannot smoke this against lib/ today because there are zero lib-side
// `?` users on a `!void` alias yet. Mirrors the shlex.syntaxerr shape
// (lib/shlex/shlex.ww:112) for the "nomem" stub.
//
// Not table-driven on purpose: same-shape `?` is a single cgen emit
// pattern, so varying the operand exercises the same asm. The two
// match arms below cover both runtime outcomes (success unwrap, error
// propagation); asm-level regressions of task #18 are gated by the
// byte-identity tests (994_w6c_ww, 995_self_rebuild).
package test;
import fmt;
type nomem = !void;
fn stub(fail: i64) (i64 | nomem) = {
if (fail != 0i64) { let e: nomem; return e; };
return 42i64;
};
fn caller(fail: i64) (i64 | nomem) = {
let v = stub(fail)?;
return v + 1i64;
};
export fn main() i32 = {
let rc: i32 = 0;
match (caller(0i64)) {
case let n: i64 => {
fmt.println("ok ", n);
if (n != 43i64) { rc = 1; };
};
case nomem => {
fmt.println("unexpected nomem on ok path");
rc = 2;
};
};
match (caller(1i64)) {
case let n: i64 => {
fmt.println("unexpected ", n, " on err path");
rc = 3;
};
case nomem => {
fmt.println("nomem as expected");
};
};
return rc;
};