w6c: classify tagged call-result args by the stamped type

taggedcallslot gated on an N_IDENT callee + fnretlookup, so every
N_DOT / wwi-decl'd cross-module callee (and every fn-pointer call)
returned 0 and its tagged call-result ARG fell off the cursor-push
path into a 16B scratch spill where cstage PUSHQes AX/DX (cstage keys
the same push on args[i]->type, cgen.c tagged_arg_size). Read the
stamped result type instead — the #209/#211 predicate-to-stamp
discipline, same class as the fn-value cgident fix.

Graduates BOTH remaining DATABYTEID_DIVERGED pins
(r700_strings_byteindex frame 80->64, r839_xmod_nominal_match frame
32->16) — the ledger is EMPTY; the byteid gate ran 1389 data fixtures
at 0 pinned-divergent. Lang rows cover the same-module control,
fn-pointer, float-member, and str-member shapes (byte-identical each).

Separate latent lead banked, NOT closed here: the tagged
subset-widening call arg ((i64|bool) passed as (i64|bool|void))
byte-diverges pre-existing — cstage stages through a 16B local,
wwstage passes direct; runtime-equivalent.
This commit is contained in:
2026-08-08 18:09:08 +09:00
parent 192ddd4c66
commit 854a532feb
3 changed files with 58 additions and 16 deletions

View File

@@ -0,0 +1,49 @@
// taggedarg_callresult_test — a tagged-union call RESULT passed
// directly as a call ARGUMENT rides the register cursor (PUSHQ AX/DX
// pairs), classified by the STAMPED result type (taggedcallslot); the
// old callee-name gate dropped fn-pointer and cross-module callees to
// a 16B scratch spill (the r700_strings_byteindex / r839 byteid pins;
// the corpus fixtures own the cross-module byte-id legs).
package taggedarg_callresult_test;
fn ok(v: i64) (i64 | void) = { return v; };
fn unwrap(r: (i64 | void)) i64 = {
match (r) {
case let n: i64 => return n;
case void => return -1;
};
};
@test fn samemod() void = {
assert(unwrap(ok(42)) == 42i64);
};
@test fn fnptr() void = {
let f: *fn(v: i64) (i64 | void) = &ok;
assert(unwrap(f(7)) == 7i64);
};
fn mkf(v: f64) (f64 | void) = { return v; };
fn pickf(r: (f64 | void)) i32 = {
match (r) {
case let d: f64 => return (d: i32);
case void => return -1;
};
};
@test fn floatmember() void = {
assert(pickf(mkf(5.0)) == 5);
};
fn mks(s: str) (str | void) = { return s; };
fn picks(r: (str | void)) i32 = {
match (r) {
case let s: str => return (s.len: i32);
case void => return -1;
};
};
@test fn strmember() void = {
assert(picks(mks("hello")) == 5);
};