w6c: key tagged natural-push call args on type equality, not slot size

pushargsrev's five aistagged gates (N_IDENT #55, N_CALL #21, N_INDEX
#12, N_DOT #22a, deref #35) treated a tagged arg as already-tagged
when its SLOT SIZE matched the param's. A same-slot subset union
((bool|void) into (i64|bool|void), both 16B) then natural-pushed the
narrower box's words carrying SOURCE tags — no re-layout, no
cg_widen_tag_remap twin — so the callee matched the wrong arm
(silent: probes exited 10/90 where cstage exits 30/27). cstage keys
widen detection on type equality (cgen.c:10000 same = (pu == au) ||
type_eq) and routes every non-same tagged source through the zeroed
scratch + tag remap; the slot-DIFFER wwstage path already mirrored
that byte-identically, so the fix computes cstage's same check once
(wsame) and replaces each slot-size test with it. This also erases
the last known cs!=ww shape divergence (the 16B-local staging vs
direct-push frame delta on prefix subsets).

8 subsetwiden_* fixtures own the class: call-result/ident/str-payload
/mid-arg remap (the wrong-arm shapes), prefix (the shape-divergence
repro), and bigslot/return-pos/struct-24-to-32 sibling guards. Corpus
pin 1740/343/22/209/1166/3480.
This commit is contained in:
2026-08-08 19:01:05 +09:00
parent dae219b7f6
commit cf69cf2f06
10 changed files with 139 additions and 32 deletions

View File

@@ -0,0 +1,11 @@
//ww:run-exit 30
package main;
fn mk(v: bool) (i64 | bool) = { return v; };
fn pick(r: (i64 | bool | str)) i32 = {
match (r) {
case let n: i64 => return 10;
case let b: bool => return 30;
case let s: str => return 40;
};
};
export fn main() i32 = { return pick(mk(true)); };

View File

@@ -0,0 +1,11 @@
//ww:run-exit 30
package main;
fn mk(v: bool) (i64 | bool) = { return v; };
fn pick(r: (i64 | bool | void)) i32 = {
match (r) {
case let n: i64 => return 10;
case let b: bool => return 30;
case void => return 20;
};
};
export fn main() i32 = { return pick(mk(true)); };

View File

@@ -0,0 +1,11 @@
//ww:run-exit 30
package main;
fn mk(v: bool) (bool | void) = { return v; };
fn pick(r: (i64 | bool | void)) i32 = {
match (r) {
case let n: i64 => return 10;
case let b: bool => return 30;
case void => return 20;
};
};
export fn main() i32 = { return pick(mk(true)); };

View File

@@ -0,0 +1,13 @@
//ww:run-exit 30
package main;
fn pick(r: (i64 | bool | void)) i32 = {
match (r) {
case let n: i64 => return 10;
case let b: bool => return 30;
case void => return 20;
};
};
export fn main() i32 = {
let v: (bool | void) = true;
return pick(v);
};

View File

@@ -0,0 +1,11 @@
//ww:run-exit 27
package main;
fn mk(v: bool) (bool | void) = { return v; };
fn pick3(a: i32, r: (i64 | bool | void), b: i32) i32 = {
match (r) {
case let n: i64 => return 90;
case let b2: bool => return a*10 + b;
case void => return 91;
};
};
export fn main() i32 = { return pick3(2, mk(true), 7); };

View File

@@ -0,0 +1,12 @@
//ww:run-exit 30
package main;
fn mk(v: bool) (bool | void) = { return v; };
fn wide(v: bool) (i64 | bool | void) = { return mk(v); };
fn pick(r: (i64 | bool | void)) i32 = {
match (r) {
case let n: i64 => return 10;
case let b: bool => return 30;
case void => return 20;
};
};
export fn main() i32 = { return pick(wide(true)); };

View File

@@ -0,0 +1,11 @@
//ww:run-exit 30
package main;
fn mk(s: str) (str | void) = { return s; };
fn pick(r: (i64 | str | void)) i32 = {
match (r) {
case let n: i64 => return 10;
case let s: str => { if (len(s) != 5) { return 4; }; return 30; };
case void => return 20;
};
};
export fn main() i32 = { return pick(mk("hello")); };

View File

@@ -0,0 +1,15 @@
//ww:run-exit 30
package main;
type pair = struct { a: i64, b: i64 };
fn mk(x: i64) (pair | void) = {
let p: pair; p.a = x; p.b = x + 1;
return p;
};
fn pick(r: (str | pair | void)) i32 = {
match (r) {
case let s: str => return 10;
case let p: pair => { if (p.a != 5) { return 4; }; if (p.b != 6) { return 5; }; return 30; };
case void => return 20;
};
};
export fn main() i32 = { return pick(mk(5)); };