cgen: B6-c2 call-arg family single peels fold into type_chase_named — 8 lines, loud-preserving

The exact B6-c2 set (rob b6 spec §2): :8402 (callee fn-type resolve cu),
:8435 (variadic slice param vsu), :8561/:8563 + :8577/:8579 (tagged
widen-detect pu/au pairs, arg-class + #38b MEMORY-class) + the two
LOUD-PRESERVING chases :8829 (float-struct rule-7 fatal st) and :8934
(#32 tuple-arg rule-7 fatal targ). Raw `->under` in cgen.c 49→41.

LOUD-PRESERVING discipline: the :8829/:8934 chases widen what the gate
SEES, never what it ACCEPTS. DESIGNED ACCEPTANCE NARROWING (ken b6
oracle c2): kb6_fsarg2 — a 1-level-alias float-struct from a non-ident
source previously DODGED the #271/#165 fatal via the single peel; cs
accepted and GP-passed it runtime-correct by self-consistent luck
(caller+callee agreed on the wrong transport, no SSE eightbyte). Post-
c2 cs louds with the pinned #271/#165 text. ww's cell was already loud
at its own alias-return bound (#272/#276/#277 class) — fsarg2_bound
pins BOTH texts per-stage (experr_ww). fsarg0 plain control stays loud
both stages. :8934 is WATCH-ONLY (alias tuple-args are checker-blocked
upstream, #86/#99): kb5_tuparg_c two-key cells verified unmoved
(cs ok/0 + ww ok/1).

TRAIN INVARIANT: cs-only; w6c_ww/ww_ww bit-identical to the 4cac1cb
baselines (b6bddc8e…/4e9ca874…). cs movers bounded to exactly
kb6_fsarg2 (run-cell ok/0→ERR, no asm emitted — zero run-row movers);
rest of the corpus + five mains byte-NEUTRAL; kw1_101/fill2/tuparg_c/
xampdef/amplen1 detectors unmoved; 989 ratchet zero flips. kb6_sarg /
kb6_strarg / kb6_fsarg (ident twin) latent byte-NEUTRAL per ken's
structural bound.

944_alias_cgen_b6_run grows 3→8 rows, 9→22 checks: fsarg0_loud_ctl +
fsarg2_bound (per-stage experr pins; row struct gains experr_ww for
two-site loud pairs) + fsarg_ident_ctl/sarg_2lvl/strarg_2lvl controls.
All 944-family suites green; sizelint 0.
This commit is contained in:
2026-06-06 03:51:34 +09:00
parent 1f14becdf3
commit 9659a0dfbe
2 changed files with 106 additions and 18 deletions

View File

@@ -8398,8 +8398,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
* its declared parameter type — needed to detect implicit
* widening of a concrete variant into a tagged-union slot. */
Type *callee_t = n->lhs ? n->lhs->type : NULL;
Type *cu = (callee_t && callee_t->kind == TY_NAMED) ?
callee_t->under : callee_t;
Type *cu = type_chase_named(callee_t);
Tparam *callee_params = (cu && cu->kind == TY_FN) ?
cu->params : NULL;
/* Hare-style variadic last param: gather N tail args into a
@@ -8431,8 +8430,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
argcount = nfixed + 1;
} else {
Type *vst = var_p->type;
Type *vsu = (vst && vst->kind == TY_NAMED)
? vst->under : vst;
Type *vsu = type_chase_named(vst);
Type *velem = (vsu && vsu->kind == TY_SLICE)
? vsu->sub : NULL;
int esz = (velem && velem->size)
@@ -8557,10 +8555,8 @@ cgexpr(Cg *c, Node *n, Local *locals)
Type *at = args[i] ? args[i]->type : NULL;
int psz = tagged_arg_size(p->type);
if (psz > 0) {
Type *pu = (p->type && p->type->kind == TY_NAMED)
? p->type->under : p->type;
Type *au = (at && at->kind == TY_NAMED)
? at->under : at;
Type *pu = type_chase_named(p->type);
Type *au = type_chase_named(at);
int same = (pu == au) || type_eq(p->type, at);
if (!same) {
widen[i] = 1;
@@ -8573,10 +8569,8 @@ cgexpr(Cg *c, Node *n, Local *locals)
int msz = tagged_memarg_size(p->type);
if (msz > 0) {
memarg[i] = msz;
Type *pu = (p->type && p->type->kind == TY_NAMED)
? p->type->under : p->type;
Type *au = (at && at->kind == TY_NAMED)
? at->under : at;
Type *pu = type_chase_named(p->type);
Type *au = type_chase_named(at);
int same = (pu == au) || type_eq(p->type, at);
if (!same) {
widen[i] = 1;
@@ -8824,9 +8818,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
* ≤16B struct with any float field; the wwstage
* tinfo mirror uses the same predicate). */
{
Type *st = args[i]->type;
if (st && st->kind == TY_NAMED)
st = st->under;
Type *st = type_chase_named(args[i]->type);
if (st && st->kind == TY_STRUCT
&& st->size <= 16) {
int f32;
@@ -8929,9 +8921,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
* pre-fix it fell to the scalar single-PUSHQ default
* and silently skewed every later arg register. */
if (tuparg_push == NULL) {
Type *targ = args[i]->type;
if (targ && targ->kind == TY_NAMED)
targ = targ->under;
Type *targ = type_chase_named(args[i]->type);
if (targ && targ->kind == TY_TUPLE)
fatal("#32: tuple arg from unsupported "
"source shape %d (call/ident/"

View File

@@ -29,6 +29,32 @@
* | reassign — latent control | 0/0
* dassign_2lvl | kb6_dassign: (*p).f= over alias ptr |
* | — latent control | 0/0
* ---- c2 (call-arg: :8402 :8435 :8561/:8563/:8577/:8579 --------
* + LOUD-PRESERVING :8829 :8934) ------------------------
* fsarg0_loud_ctl | kb6_fsarg0: PLAIN float-struct from |
* | a non-ident source — #271/#165 loud |
* | BOTH stages (control, twin texts) | err/err
* fsarg2_bound | kb6_fsarg2: 1-alias-level respell — |
* | pre-c2 the :8829 single-peel let |
* | the alias DODGE the fatal; cs GP- |
* | passed by self-consistent luck. |
* | DESIGNED NARROWING: cs now louds |
* | with the pinned #271/#165 text |
* | ("widen what the gate SEES, never |
* | what it ACCEPTS"). ww's loud is its |
* | own alias-return bound (#272/#277 |
* | class, experr_ww) — per-stage texts | err/err
* fsarg_ident_ctl | kb6_fsarg: IDENT-source alias twin |
* | — ident domain out of the :8829 |
* | gate, latent control | 0/0
* sarg_2lvl | kb6_sarg: >16B alias struct arg — |
* | latent (B5 helper chases carry the |
* | type layer) | 0/0
* strarg_2lvl | kb6_strarg: alias str arg — latent | 0/0
* (:8934 tuple loud is WATCH-ONLY: alias spellings are |
* checker-blocked upstream (#86/#99) — the pin is the b5 |
* suite's tuparg_cast_bound99 two-key cells, which must |
* not move.) |
*
* K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant)
* and assert cstage/wwstage asm byte-id. K_BUILDERR rows must FAIL
@@ -131,6 +157,78 @@ static const struct row rows[] = {
" if (x.b != 9) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
/* ---- c2: call-arg family */
{ "fsarg0_loud_ctl",
"package main;\n"
"type fs0 = struct { x: f64 };\n"
"fn mk() fs0 = {\n"
" let s: fs0; s.x = 2.5;\n"
" return s;\n"
"};\n"
"fn g(p: fs0) f64 = { return p.x; };\n"
"export fn main() i32 = {\n"
" if (g(mk()) != 2.5) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_BUILDERR,
"#271/#165: float-bearing struct arg from a non-ident source",
NULL },
/* DESIGNED ACCEPTANCE NARROWING (B6-c2): pre-c2 cs accepted and
* GP-passed this float struct correct-by-self-consistent-luck
* (caller+callee agreed on the wrong transport) — the :8829
* single peel let a 1-level alias dodge the rule-7 fatal. The
* chase widens what the gate SEES; the loud stays loud for the
* shapes it guards. ww's cell was ALREADY loud at its own
* alias-return bound (#272/#276/#277 class) — different site,
* per-stage experr. */
{ "fsarg2_bound",
"package main;\n"
"type fs0 = struct { x: f64 };\n"
"type fs = fs0;\n"
"fn mk() fs = {\n"
" let s: fs; s.x = 2.5;\n"
" return s;\n"
"};\n"
"fn g(p: fs) f64 = { return p.x; };\n"
"export fn main() i32 = {\n"
" if (g(mk()) != 2.5) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_BUILDERR,
"#271/#165: float-bearing struct arg from a non-ident source",
"#272/#276/#277: aggregate return reaches scalar default" },
{ "fsarg_ident_ctl",
"package main;\n"
"type fs0 = struct { x: f64 };\n"
"type fs = fs0;\n"
"fn mk() fs0 = {\n"
" let s: fs0; s.x = 2.5;\n"
" return s;\n"
"};\n"
"fn g(p: fs) f64 = { return p.x; };\n"
"export fn main() i32 = {\n"
" let v: fs = mk();\n"
" if (g(v) != 2.5) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
{ "sarg_2lvl",
"package main;\n"
"type big0 = struct { a: i64, b: i64, c: i64 };\n"
"type big = big0;\n"
"fn g(p: big) i64 = { return p.a + p.c; };\n"
"export fn main() i32 = {\n"
" let s: big; s.a = 4; s.b = 5; s.c = 9;\n"
" if (g(s) != 13) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
{ "strarg_2lvl",
"package main;\n"
"type ms0 = str;\n"
"type ms = ms0;\n"
"fn g(s: ms) i64 = { return len(s): i64; };\n"
"export fn main() i32 = {\n"
" let a: ms = \"hello\";\n"
" if (g(a) != 5) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
};
static int