w6c+w6c_ww: tuple-let receive keyed on type classify, not producer shape (C-t1, #33)

wwstage cglet's tuple receive was producer-SHAPE-keyed: the mixed
str/scalar arm required s0_is_str != s1_is_str (syntactic) and the
rt16 arm required an N_CALL rhs (rettupleof), so a scalar-scalar tuple
LITERAL `let t: (u32,u32) = (3,4)` matched neither and fell to the
generic single-word store — word 1 silently dropped (#209/#211-class
syntactic-vs-type keying). cstage's twin arm was sz==16/32 magic-size
keyed, so 24B 3-scalar tuples dropped words 2+ on BOTH sources.

Both stages now key the same way: declared-type TY_TUPLE + in-cap
register classify (cg_sret_retsize / sretretsize == 0, the shared
SSoT), alias-peeled; the two wwstage shape arms collapse into one
type-keyed arm walking the declared element list (the #240 lesson —
never the producer's). Over-cap falls through to the sret receive
exactly as before; unannotated `let t = f()` rides inferletcalltype.

941 grows the t1 rows: lit packed/16B/3-scalar + call 3-scalar fail at
the C-t0 parent (10/39 checks — wwstage lit halves AND both-stage
24B halves), mixed-lit + unannotated-call anchor the untouched paths.

Filed while probing: cstage silently accepts an over-cap tuple-LITERAL
let where wwstage loud-stops (pre-existing at master, task #64).
This commit is contained in:
2026-06-04 18:28:30 +09:00
parent fdfc2ce318
commit 12af54f9f8
5 changed files with 237 additions and 281 deletions

View File

@@ -163,6 +163,75 @@ static const struct row rows[] = {
" if (b != 4) { return 2; };\n"
" return 0;\n"
"};\n", 0 },
/* ---- C-t1 (#33): the let RECEIVE re-keyed onto the declared
* type's register classify. Pre-C-t1 wwstage keyed on producer
* SHAPE (mixed-str syntactic / rettupleof N_CALL) so a
* scalar-scalar LITERAL matched neither and dropped word 1;
* cstage keyed on sz==16/32 so 24B 3-scalar shapes dropped words
* on BOTH sources. ---- */
{ "t1_lit_packed",
"package main;\n"
"fn second() u32 = {\n"
" let t: (u32, u32) = (3, 4);\n"
" if (t.0 != 3) { return 99; };\n"
" return t.1;\n"
"};\n"
"export fn main() i32 = {\n"
" if (second() != 4) { return 1; };\n"
" return 0;\n"
"};\n", 0 },
{ "t1_lit_16",
"package main;\n"
"export fn main() i32 = {\n"
" let t: (i64, i64) = (3, 4);\n"
" if (t.0 != 3) { return 1; };\n"
" if (t.1 != 4) { return 2; };\n"
" return 0;\n"
"};\n", 0 },
{ "t1_lit_mixed",
"package main;\n"
"export fn main() i32 = {\n"
" let t: (i64, str) = (12, \"wxyz\");\n"
" if (t.0 != 12) { return 1; };\n"
" if (len(t.1) != 4) { return 2; };\n"
" return 0;\n"
"};\n", 0 },
{ "t1_lit_3scalar",
"package main;\n"
"fn second() i64 = {\n"
" let t: (i64, i64, i64) = (3, 4, 5);\n"
" if (t.0 != 3) { return -1; };\n"
" if (t.1 != 4) { return -2; };\n"
" return t.2;\n"
"};\n"
"export fn main() i32 = {\n"
" if (second() != 5) { return 1; };\n"
" return 0;\n"
"};\n", 0 },
{ "t1_call_3scalar",
"package main;\n"
"fn f() (i64, i64, i64) = {\n"
" return (7, 8, 9);\n"
"};\n"
"export fn main() i32 = {\n"
" let t: (i64, i64, i64) = f();\n"
" if (t.0 != 7) { return 1; };\n"
" if (t.1 != 8) { return 2; };\n"
" if (t.2 != 9) { return 3; };\n"
" return 0;\n"
"};\n", 0 },
{ "t1_call_noannot_neutral",
"package main;\n"
"fn f() (i64, i64) = {\n"
" return (3, 4);\n"
"};\n"
"export fn main() i32 = {\n"
" let t = f();\n"
" if (t.0 != 3) { return 1; };\n"
" if (t.1 != 4) { return 2; };\n"
" return 0;\n"
"};\n", 0 },
};
/* build+run via a driver (ww / ww_ww); returns 0 pass, nonzero fail. */