w6c+w6c_ww: loud-stop non-ident/non-local append spread source (#34 review)

A spread whose source was not a local ident fell PAST the spread arm:
cstage continued into the single-value stores with the N_SPREAD node
(garbage store), wwstage silently SKIPPED the value entirely — a silent,
cs!=ww-divergent miscompile (append(ys, f()...): cs exit 0 / ww exit 144,
want 3), reachable for every element kind and predating #34 for scalars.
Both stages now rule-7 loud-stop the shape (deferred, task #37).

Also pins the widener's already-tagged single-value source path
(tagged_ident_src row, i64 + bool members) and adds the
spread_call_loudstop BUILD_FAIL row — test 800 is now 15 rows / 43
fixtures.
This commit is contained in:
2026-06-04 02:27:06 +09:00
parent 70fa9e2264
commit 36be9f469d
5 changed files with 104 additions and 9 deletions

View File

@@ -60,10 +60,18 @@
* | scratch slots where wwstage dedups) |
* spread_str | append(ys, xs...) of []str + single | 7
* spread_tagged | append(ys, xs...) of [](i64|bool) | 42
* tagged_ident_src | append of ALREADY-TAGGED locals | 42
* | (i64 + bool members) — the widener's |
* | already-tagged source path. |
* struct_call_loudstop | append(xs, f()) struct-from-call is | BUILD_FAIL
* | the deferred source shape — must |
* | fail LOUD on both stages (rule-7), |
* | never silently store one word. |
* spread_call_loudstop | append(ys, f()...) non-ident spread | BUILD_FAIL
* | source — pre-review this fell PAST |
* | the spread arm (cstage garbage store |
* | vs wwstage silent skip, divergent); |
* | now a rule-7 loud-stop (task #37). |
*
* Every non-BUILD_FAIL row also asserts cstage/wwstage asm byte-id,
* which subsumes the frame-size canary (TEXT main,$N) — the @tagbase/
@@ -251,6 +259,28 @@ static const struct row rows[] = {
"};\n",
42 },
{ "tagged_ident_src",
"package main;\n"
"type cell = (i64 | bool);\n"
"export fn main() i32 = {\n"
"\tlet xs: []cell = [];\n"
"\tlet c: cell = 40i64;\n"
"\tlet b: cell = true;\n"
"\tappend(xs, c);\n"
"\tappend(xs, b);\n"
"\tlet r: i32 = 0;\n"
"\tmatch (xs[0]) {\n"
"\tcase let v: i64 => r += v: i32;\n"
"\tcase bool => r = 99;\n"
"\t};\n"
"\tmatch (xs[1]) {\n"
"\tcase i64 => r = 98;\n"
"\tcase let w: bool => { if (w) { r += 2; }; };\n"
"\t};\n"
"\treturn r;\n"
"};\n",
42 },
{ "struct_call_loudstop",
"package main;\n"
"type pt = struct { x: i32, y: i32, z: i64 };\n"
@@ -263,6 +293,21 @@ static const struct row rows[] = {
"\treturn 0;\n"
"};\n",
BUILD_FAIL },
{ "spread_call_loudstop",
"package main;\n"
"fn mks() []str = {\n"
"\tlet xs: []str = [];\n"
"\tlet a: str = \"abc\";\n"
"\tappend(xs, a);\n"
"\treturn xs;\n"
"};\n"
"export fn main() i32 = {\n"
"\tlet ys: []str = [];\n"
"\tappend(ys, mks()...);\n"
"\treturn ys[0].len: i32;\n"
"};\n",
BUILD_FAIL },
};
static int