Files
ww/test/wcc/944_alias_accept_run.c
Hojun-Cho 9bd0d8bc81 wcc: #5 F1 promote type_chase_named + transitive-peel acceptance align-cs-up
Promote type_chase_named from cmd/w6c/cgen.c (static) to cmd/wcc/type.c
(exported via ww.h) and re-route every checker single-NAMED-peel through
it: check.c's ~28 inline ternaries + 3 ad-hoc loops, type.c's
assignability/untyped/borrow/opaque peels. type_eq's nominal identity
(check.c:114) and the resolve machinery guards stay untouched.

The re-route IS the acceptance align-up — cstage loud-rejected alias
shapes wwstage accepts AND runs Hare-right (F0 census, harec dealiases
at every consumer):
- #54 binop alias-vs-base: unify_arith gains the harec type_promote arm
  (ref/harec/src/check.c:1083-1105) — one-sided alias + dealias-equal
  promotes to the ALIAS side; alias-vs-alias stays rejected.
- alias-cond family: if/for/&&/||/! chase-then-bool (harec
  check.c:2141/2515/3229/3572). assert stays loud (F0 2a symmetric).
- #70 field access through 2-level alias chains (ken c3_chain3).
- assignability through the full chain (harec types.c:989-996
  dealias-both): return/init/assign legs, F0 8b idx/slice walls.
- alias-of-ptr deref (harec types.c:19-22 type_dereference).

The widening reaches cgen arms whose own single peels then misbehaved —
both classes are closed IN THIS COMMIT so no intermediate state ships a
loud->silent flip (bisect no-silent invariant):
- index family: the 8b acceptance hit ptr-load base + esz=1 (SEGV /
  prefix-luck) — idx_eff + the N_INDEX read / index-write / &base[i] /
  N_SLICE (expr + call-arg) / N_FORRANGE / aggarg_srcaddr-index /
  castsrcprim-dot / match-field base classifies chase.
- kind classifiers (ken #61-root-verify v3 find): a 2-level f64 alias
  param reached cg_isfloat's single peel and classified INT — silent
  wrong-register-class. cg_isfloat / type_isf32 / fld_isfloat /
  type_isstr / type_isslice chase. ken's v3 row is pinned with credit.

Bootstrap asm is byte-identical before/after (w6c on every
main.combined.ww cmp-equal vs a pristine 738d7f4 scratch; 989
lib_byteid pins unchanged): 2-level chains were checker-walled pre-F1,
so no previously-accepted program changes shape.

test: 944_alias_accept_run (20 rows): acceptance graduations pinned
runtime + byte-id both stages; idx/slice/range/slice-param rows cs-only
until the wwstage #60 esz family lands (F2 batch 1); cs-only
harec-parity loud pin for alias-vs-alias binop; assert stays-loud row;
ken-v3 + f64/str/slice kind rows. Mutation-checked at 738d7f4.

reviewer-F1 fold — the same invariant, outside the F0 census: this
commit ADMITS 2+-level alias slice/str/aggregate types in STRUCT FIELD
position, therefore this commit must keep them correct-or-loud. The
cgen FIELD-TYPE gates single-peeled, so the slice/str 3-word arms fell
to word0-only scalar tails — accept-and-corrupt, ww correct, every
shape loud at the pristine base. Chased (probe-proven, byte-id
graduations): single-dot field store + via-ptr twin, struct-lit fill,
chained store-walk LEAF (the #71 walk chases hops, not leaves),
chained-ptr-field store, single-dot / via-ptr / chained-walk field
reads (clobber-probed — word0 reads luck-passed on stale BX/CX). The
six unprobed sibling gates (indexed-elem store/read, ptr-chain read,
heap fill, tuple-elem read, static emit) hard-error via
fld_alias_tripwire on a 2+-level alias over an aggregate base, citing
task #73 (the family's scheduled chase); <=1-level and scalar bases
never fire — zero behavior change for any pre-#5-legal program (five
selfhost mains cmp-identical vs the pristine 738d7f4 scratch).
test: 944 +11 rows (9 K_RUN byte-id, wholeread K_RUN_CS [#60 ww half +
pre-existing 1-level read-spine divergence], #73 tripwire
K_BUILDERR_CS pin); 1-level controls per gate in /tmp/revF1.
2026-06-05 18:33:47 +09:00

712 lines
23 KiB
C

/*
* 944_alias_accept_run — #5 alias arc F1: cstage acceptance ALIGN-UP
* through the transitive TY_NAMED chase (type_chase_named, promoted to
* cmd/wcc/type.c). harec dealiases at every promotion/cond/assign
* consumer (ref/harec/src/types.c:53 type_dealias; :989-996
* type_is_assignable; src/check.c:1083-1105 type_promote; :2141 if,
* :2515 for, :3229 &&/||, :3572 !) — wwstage already accepted these
* shapes AND ran them Hare-right (F0 census /tmp/f0/livelist.md), so
* the cstage single-peel rejects were the lean side aligned UP.
*
* row | shape | want
* ---------------------+--------------------------------------+-----
* binop_alias_base | myint + int (F0 m1_binop) | 0
* binop_2level | myint2 % int, myu / u32 (m1_binop2) | 0
* ret_through_2level | fn(x: myint2) int = x * 2 | 0
* assign_alias_alias | k1 → k2 (same base; harec dealias- |
* | both admits) | 0
* binop_alias_vs_alias | k1 + k2 — cstage stays LOUD per |
* | harec type_promote ALIAS+ALIAS→NULL | err(cs)
* cond_if/for/bang/ | alias-of-bool at every cond consumer |
* andor/fnparam | (F0 m2_* family) | 0
* assert_stays_loud | alias-bool assert — BOTH stages loud |
* | (F0 2a DISSOLVED-SYMMETRIC; the Hare |
* | widening is parked on #5) | err
* dot_2level | field access via a3=b3=c3=struct |
* | (task #70, ken c3_chain3) | 0
* deref_alias_ptr | *p through pi2=pi=*int | 0
* idx/slice/range_ | index/slice/for-range over 2-level |
* 2level, slice_arg | alias bases (F0 8b) — cs cgen index |
* | family chased (idx_eff + base |
* | classify); CS-ONLY rows: the wwstage |
* | half is the task-#60 esz family (F2 |
* | batch 1) — flip to K_RUN when it |
* | lands | 0(cs)
* float_alias_param* / | ken-v3 leg: 2-level f64/str/slice |
* str_alias_2level / | aliases at the cgen KIND classifiers |
* slice_alias_param | (slice leg cs-only, #60) | 0
* slicefield_* / | reviewer-F1 leg: 2-level alias of |
* strfield_store_2lvl | slice/str as a STRUCT FIELD type — |
* | cgen field gates chased (stores, |
* | struct-lit, walk leaves, reads); |
* | unprobed gates LOUD-tripwired (#73, |
* | K_BUILDERR_CS pin) | 0
*
* K_RUN rows also assert cstage/wwstage asm byte-id (acceptance
* graduations land byte-identical — F0's accept side was wwstage).
* K_RUN_CS / K_BUILDERR_CS rows run the cstage driver only, each
* citing the task that graduates them. binop_alias_vs_alias is
* CS-only loud: the wwstage checker stays silent on typed mismatches
* by design (5-lite discipline) — cs pins the harec-parity reject.
* NNN<950, self-contained (/tmp, no imports) — rule-14's selfhost-
* sibling race does not apply (941/944 precedent).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa), cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
#define K_RUN 0 /* build+run BOTH drivers, exit==want, + byte-id */
#define K_BUILDERR 1 /* build FAILS with experr on BOTH drivers */
#define K_RUN_CS 2 /* cstage only — ww half pending (cite at row) */
#define K_BUILDERR_CS 3 /* cstage-only loud (ww silent by design) */
struct row { const char *label; const char *src; int want;
int kind; const char *experr; };
/* errlog_has — a BUILDERR row must fail WITH its diagnostic; any other
* failure (parse error, crash, hang-kill) is a vacuous reject (940
* precedent). */
static int
errlog_has(const char *path, const char *needle)
{
FILE *f = fopen(path, "rb");
if (!f) return 0;
char buf[8192];
size_t got = fread(buf, 1, sizeof buf - 1, f);
fclose(f);
buf[got] = '\0';
return strstr(buf, needle) != NULL;
}
static const struct row rows[] = {
{ "binop_alias_base",
"package main;\n"
"type myint = int;\n"
"export fn main() i32 = {\n"
" let a: myint = 5;\n"
" let b: int = 3;\n"
" let c = a + b;\n"
" if (c != 8) { return 1; };\n"
" let d: myint = 2;\n"
" if (a * d != 10) { return 2; };\n"
" if (a < b) { return 3; };\n"
" if (a - b != 2) { return 4; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "binop_2level",
"package main;\n"
"type myint = int;\n"
"type myint2 = myint;\n"
"type myu = u32;\n"
"export fn main() i32 = {\n"
" let a: myint2 = 7;\n"
" let b: int = 2;\n"
" if (a % b != 1) { return 1; };\n"
" let u: myu = 10: u32;\n"
" let v: u32 = 3: u32;\n"
" if (u / v != 3: u32) { return 2; };\n"
" if (u + v != 13: u32) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "ret_through_2level",
"package main;\n"
"type myint = int;\n"
"type myint2 = myint;\n"
"fn dbl(x: myint2) int = {\n"
" return x * 2;\n"
"};\n"
"export fn main() i32 = {\n"
" let a: myint2 = 21;\n"
" if (dbl(a) != 42) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "assign_alias_alias",
"package main;\n"
"type k1 = int;\n"
"type k2 = int;\n"
"export fn main() i32 = {\n"
" let x: k1 = 5;\n"
" let y: k2 = x;\n"
" if (y != 5) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* harec type_promote: ALIAS+ALIAS → NULL even on a shared base
* (ref/harec/src/check.c:1087-1089). wwstage's checker is silent
* on typed mismatches (5-lite) — cs-only pin. */
{ "binop_alias_vs_alias",
"package main;\n"
"type k1 = int;\n"
"type k2 = int;\n"
"export fn main() i32 = {\n"
" let x: k1 = 5;\n"
" let y: k2 = 3;\n"
" if (x + y != 8) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_BUILDERR_CS, "operands have differing types" },
{ "cond_if",
"package main;\n"
"type myb = bool;\n"
"export fn main() i32 = {\n"
" let b: myb = true;\n"
" if (b) { return 0; };\n"
" return 1;\n"
"};\n", 0, K_RUN, NULL },
{ "cond_for",
"package main;\n"
"type myb = bool;\n"
"export fn main() i32 = {\n"
" let b: myb = true;\n"
" let i: int = 0;\n"
" for (b) {\n"
" i = i + 1;\n"
" if (i >= 3) { b = false; };\n"
" };\n"
" if (i != 3) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "cond_bang",
"package main;\n"
"type myb = bool;\n"
"export fn main() i32 = {\n"
" let b: myb = false;\n"
" let n = !b;\n"
" if (!n) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "cond_andor",
"package main;\n"
"type myb = bool;\n"
"export fn main() i32 = {\n"
" let b: myb = true;\n"
" let c: myb = false;\n"
" if (b && !c) { } else { return 1; };\n"
" if (c || b) { } else { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "cond_fnparam",
"package main;\n"
"type myb = bool;\n"
"fn pick(b: myb) i32 = {\n"
" if (b) { return 0; };\n"
" return 1;\n"
"};\n"
"export fn main() i32 = {\n"
" let b: myb = true;\n"
" return pick(b);\n"
"};\n", 0, K_RUN, NULL },
{ "assert_stays_loud",
"package main;\n"
"type myb = bool;\n"
"export fn main() i32 = {\n"
" let b: myb = true;\n"
" assert(b);\n"
" return 0;\n"
"};\n", 0, K_BUILDERR, "assert: cond must be bool" },
{ "dot_2level",
"package main;\n"
"type a3 = b3;\n"
"type b3 = c3;\n"
"type c3 = struct { x: size, y: size, z: size };\n"
"export fn main() i32 = {\n"
" if (size(a3) != 24) { return 1; };\n"
" if (size((void | a3)) != 32) { return 2; };\n"
" let v: a3;\n"
" v.x = 1; v.y = 2; v.z = 3;\n"
" if (v.x + v.y + v.z != 6) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "deref_alias_ptr",
"package main;\n"
"type pi = *int;\n"
"type pi2 = pi;\n"
"export fn main() i32 = {\n"
" let v: int = 41;\n"
" let p: pi2 = &v;\n"
" if (*p != 41) { return 1; };\n"
" *p = 7;\n"
" if (v != 7) { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* ---- reviewer-F1 find: 2-level alias of slice/str as a STRUCT
* FIELD type. The acceptance above admits every construction; the
* cgen FIELD-TYPE gates single-peeled, so the slice/str 3-word
* arms fell to word0-only scalar tails — SILENT wrong (ww correct,
* every shape LOUD at pristine 738d7f4 = opened by this commit).
* Chased gates: single-dot store (+via-ptr), struct-lit fill,
* chained store-walk leaf, chained-ptr-field store, single-dot /
* via-ptr / chained-walk reads. Each row pins one gate; the
* noise() call clobbers BX/CX so stale-register luck can't pass a
* word0-only header. Unprobed sibling gates are LOUD-tripwired,
* pinned by the #73 row at the end of this block. Rows whose
* `.len` readback rides the chained-dot READ walk are K_RUN_CS
* here (runtime-correct both stages; cs takes the generic spine
* pre-#71) and flip to K_RUN at the #71 walk-chase commit, which
* graduates their byte-id. */
{ "slicefield_store_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let b: box;\n"
" b.n = 5;\n"
" b.s = a[0:3];\n"
" if (b.n != 5) { return 9; };\n"
" if (b.s[0] != 700) { return 1; };\n"
" if (b.s[2] != 900) { return 2; };\n"
" if (b.s.len != 3) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "slicefield_range_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let b: box;\n"
" b.s = a[0:3];\n"
" b.n = 5;\n"
" if (b.s.len != 3) { return 1; };\n"
" if (b.s[2] != 900) { return 2; };\n"
" for (let x .. b.s) {\n"
" if (x < 700) { return 3; };\n"
" };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "strfield_store_2lvl",
"package main;\n"
"type s1t = str;\n"
"type s2t = s1t;\n"
"type box = struct { s: s2t, n: int };\n"
"export fn main() i32 = {\n"
" let b: box;\n"
" b.s = \"hello\";\n"
" b.n = 5;\n"
" if (b.s.len != 5) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "slicefield_structlit_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let b: box = box { s = a[0:3], n = 5: int };\n"
" if (b.n != 5) { return 1; };\n"
" if (b.s.len != 3) { return 2; };\n"
" if (b.s[2] != 900) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "slicefield_viaptr_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let b: box;\n"
" let p = &b;\n"
" p.s = a[0:3];\n"
" if (p.s.len != 3) { return 1; };\n"
" if (p.s[2] != 900) { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "slicefield_chainstore_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type inner = struct { s: sl2 };\n"
"type outer = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let v: outer;\n"
" v.i.s = a[0:3];\n"
" if (v.i.s.len != 3) { return 1; };\n"
" if (v.i.s[2] != 900) { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "slicefield_ptrchain_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type inner = struct { s: sl2, n: int };\n"
"type outer = struct { pi: *inner };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let i: inner;\n"
" i.n = 1;\n"
" let v: outer;\n"
" v.pi = &i;\n"
" v.pi.s = a[0:3];\n"
" if (i.s.len != 3) { return 1; };\n"
" if (i.s[2] != 900) { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */
{ "slicefield_chainread_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type inner = struct { s: sl2 };\n"
"type outer = struct { i: inner };\n"
"fn noise(x: int) int = {\n"
" return x * 7 + 3;\n"
"};\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let v: outer;\n"
" v.i.s = a[0:3];\n"
" let k = noise(9);\n"
" if (k != 66) { return 9; };\n"
" let w = v.i.s;\n"
" if (w.len != 3) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "slicefield_ptrread_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"fn noise(x: int) int = {\n"
" return x * 7 + 3;\n"
"};\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let b: box;\n"
" b.s = a[0:3];\n"
" let p = &b;\n"
" let k = noise(9);\n"
" if (k != 66) { return 9; };\n"
" let w = p.s;\n"
" if (w.len != 3) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* whole-field read into a local: cs runtime-correct post-chase
* (the clobbered-register r1b probe), but the `let w = b.s`
* receive spine diverges cs vs ww at ONE level already (byte-id
* NO at pristine 738d7f4 = pre-existing, #71-style divergence,
* filed under #73's census) and ww's `w[i]` read is the task-#60
* esz family — cs-only until both land. */
{ "slicefield_wholeread_2lvl",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"fn noise(x: int) int = {\n"
" return x * 7 + 3;\n"
"};\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let b: box;\n"
" b.s = a[0:3];\n"
" let k = noise(9);\n"
" if (k != 66) { return 9; };\n"
" let w = b.s;\n"
" if (w.len != 3) { return 1; };\n"
" if (w[2] != 900) { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #60 (F2 batch 1) */
/* #73 tripwire pin: the UNPROBED single-peel field gates
* (indexed-elem store/read, ptr-chain read, heap fill, tuple-elem
* read, static emit) hard-error on a 2+-level alias over an
* aggregate base instead of emitting a word0 tail. ww accepts and
* runs these — cs-only loud until #73's chase. 1-level controls
* verified per gate (/tmp/revF1 t*c probes). */
{ "slicefield_idx_tripwire_73",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"type box = struct { s: sl2, n: int };\n"
"export fn main() i32 = {\n"
" let a: [3]int = [700: int, 800: int, 900: int];\n"
" let xs: [2]box;\n"
" xs[0].s = a[0:3];\n"
" if (xs[0].s.len != 3) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_BUILDERR_CS,
"unswept single-peel gate (#73)" },
/* Values >255 break the esz=1 prefix-luck; the write-then-read
* pins the IMULQ stride on both the read and write spines. */
{ "idx_2level",
"package main;\n"
"type arr = [4]int;\n"
"type arr2 = arr;\n"
"export fn main() i32 = {\n"
" let a: arr2 = [1000: int, 2000: int, 3000: int, 4000: int];\n"
" if (a[2] != 3000) { return 1; };\n"
" a[1] = 9999;\n"
" if (a[1] != 9999) { return 2; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #60 (F2 batch 1) */
{ "slice_2level",
"package main;\n"
"type sl = []int;\n"
"type sl2 = sl;\n"
"export fn main() i32 = {\n"
" let a: [4]int = [1000: int, 2000: int, 3000: int, 4000: int];\n"
" let s: sl2 = a[1:3];\n"
" if (s.len != 2) { return 1; };\n"
" if (s[0] != 2000) { return 2; };\n"
" s[1] = 7777;\n"
" if (a[2] != 7777) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #60 (F2 batch 1) */
{ "range_2level",
"package main;\n"
"type arr = [4]int;\n"
"type arr2 = arr;\n"
"export fn main() i32 = {\n"
" let a: arr2 = [1: int, 2: int, 3: int, 4: int];\n"
" let sum: int = 0;\n"
" for (let x .. a) {\n"
" sum = sum + x;\n"
" };\n"
" if (sum != 10) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #60 (F2 batch 1) */
{ "slice_of_alias_arg",
"package main;\n"
"type arr = [4]int;\n"
"type arr2 = arr;\n"
"fn sum(s: []int) int = {\n"
" let t: int = 0;\n"
" for (let x .. s) { t = t + x; };\n"
" return t;\n"
"};\n"
"export fn main() i32 = {\n"
" let a: arr2 = [1000: int, 2000: int, 3000: int, 4000: int];\n"
" let s = a[1:3];\n"
" if (s.len != 2) { return 1; };\n"
" if (s[1] != 3000) { return 2; };\n"
" if (sum(a[0:4]) != 10000) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #60 (F2 batch 1) */
/* ---- ken-v3 leg: the acceptance align above opens 2-level
* float/str/slice aliases to the cgen KIND classifiers
* (cg_isfloat/type_isf32/fld_isfloat/type_isstr/type_isslice),
* whose single peel classed them scalar/INT — the f64-alias param
* would read the wrong register class (cs exit 1 SILENT, ww
* correct). The classifiers chase IN THIS SAME COMMIT so the
* widening never ships a loud->silent flip (rule 7; ken root-
* verify /tmp/ken_f1, his v3 row below). */
{ "float_alias_param_kenv3",
"package main;\n"
"type fa = fb;\n"
"type fb = f64;\n"
"fn take(x: fa) f64 = {\n"
" return x * 2.0;\n"
"};\n"
"export fn main() i32 = {\n"
" if (take(1.5) != 3.0) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "float_alias_param",
"package main;\n"
"type f1t = f64;\n"
"type f2t = f1t;\n"
"fn half(x: f2t) f64 = {\n"
" return x / 2.0;\n"
"};\n"
"export fn main() i32 = {\n"
" let v: f2t = 5.0;\n"
" if (half(v) != 2.5) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "str_alias_2level",
"package main;\n"
"type s1t = str;\n"
"type s2t = s1t;\n"
"fn taillen(s: s2t) int = {\n"
" return (s.len: int);\n"
"};\n"
"export fn main() i32 = {\n"
" let v: s2t = \"hello\";\n"
" if (v.len != 5) { return 1; };\n"
" if (taillen(v) != 5) { return 2; };\n"
" let w: s2t = v;\n"
" if (w.len != 5) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* slice leg: cs classify fixed; the ww half of the indexed read
* is the task-#60 esz family — cs-only until F2. Values >255
* break the esz=1 prefix-luck. */
{ "slice_alias_param",
"package main;\n"
"type b1 = []int;\n"
"type b2 = b1;\n"
"fn first(s: b2) int = {\n"
" return s[0];\n"
"};\n"
"export fn main() i32 = {\n"
" let a: [3]int = [1000: int, 2000: int, 3000: int];\n"
" let s: b2 = a[0:3];\n"
" if (first(s) != 1000) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #60 (F2 batch 1) */
};
static int
run_driver(const char *driver, const struct row *r, int i)
{
char src[96], tmpdir[96], errf[96], cmd[1024];
snprintf(src, sizeof src, "/tmp/aac_%d_%d.ww", getpid(), i);
snprintf(tmpdir, sizeof tmpdir, "/tmp/aac_%d_d_%d", getpid(), i);
snprintf(errf, sizeof errf, "/tmp/aac_%d_e_%d", getpid(), i);
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
fclose(f);
mkdir(tmpdir, 0755);
snprintf(cmd, sizeof cmd,
"cd %s && timeout 20 %s build %s >/dev/null 2>%s",
tmpdir, driver, src, errf);
int brc = runwait(cmd);
if (r->kind == K_BUILDERR || r->kind == K_BUILDERR_CS) {
int ok = (brc != 0)
&& (r->experr == NULL || errlog_has(errf, r->experr));
if (!ok)
fprintf(stderr, "row[%s]: %s expected loud builderr "
"\"%s\" (brc=%d)\n", r->label, driver,
r->experr ? r->experr : "", brc);
unlink(src); unlink(errf); rmdir(tmpdir);
return ok ? 0 : 1;
}
if (brc != 0) {
fprintf(stderr, "row[%s]: build via %s failed\n",
r->label, driver);
unlink(src); unlink(errf); rmdir(tmpdir);
return -1;
}
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char outbin[256];
snprintf(outbin, sizeof outbin, "%s/%s", tmpdir, base);
char *dot = strrchr(outbin, '.');
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
int got = runwait(outbin);
unlink(src); unlink(outbin); unlink(errf); rmdir(tmpdir);
if (got != r->want) {
fprintf(stderr, "row[%s]: %s exit %d, want %d\n",
r->label, driver, got, r->want);
return 1;
}
return 0;
}
static int
asm_byte_identical(const char *bin, const struct row *r, int i)
{
char src[96], cs[96], ws[96], cmd[1024];
snprintf(src, sizeof src, "/tmp/aac_asm_%d_%d.ww", getpid(), i);
snprintf(cs, sizeof cs, "/tmp/aac_asm_%d_%d_c.s", getpid(), i);
snprintf(ws, sizeof ws, "/tmp/aac_asm_%d_%d_w.s", getpid(), i);
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c errored\n", r->label);
unlink(src);
return -1;
}
snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null",
bin, ws, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label);
unlink(src); unlink(cs);
return -1;
}
int rc = slurp_eq(cs, ws);
if (rc != 0)
fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n",
r->label);
unlink(src); unlink(cs); unlink(ws);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[2080];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cdrv[2120], wdrv[2120];
snprintf(cdrv, sizeof cdrv, "%s/ww", bin);
snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin);
int n = (int)(sizeof rows / sizeof rows[0]);
int total = 0, fail = 0;
for (int i = 0; i < n; i++) {
total++;
if (run_driver(cdrv, &rows[i], i) != 0) fail++;
}
if (access(wdrv, X_OK) == 0) {
for (int i = 0; i < n; i++) {
if (rows[i].kind == K_RUN_CS
|| rows[i].kind == K_BUILDERR_CS)
continue;
total++;
if (run_driver(wdrv, &rows[i], i) != 0) fail++;
}
for (int i = 0; i < n; i++) {
if (rows[i].kind != K_RUN)
continue;
total++;
if (asm_byte_identical(bin, &rows[i], i) != 0) fail++;
}
}
if (fail) {
fprintf(stderr, "alias_accept: %d/%d checks failed\n",
fail, total);
return 1;
}
printf("alias_accept: %d/%d ok\n", total, total);
return 0;
}