wcc_ww/check: c4 #80 bare-binder forrange dealiases the iterable's type expr

F2a batch-4 c4. RE-PROBED AFTER c1 per spec: still live at the c3
train base with a REBUILT w6c_ww (the mechanical tichase collapse
didn't cover it — this read is AST-node-keyed, not tinfo-keyed).

REPRO (.ai/scratch/repro_f2a1_b4.ww): `untyped_lit * rangevar` over a
range-for of an alias-typed slice (`type slk = []int`) — wwstage
checker dies "asserttyped: bin" at the binop; cs accepts and runs 0.

TRACE: check.ww resolvewalk N_FORRANGE bare-binder arm — the binder's
element type comes from kind-testing the scrutinee's type expr
(N_TSLICE/N_TARRAY), but an alias-typed iterable arrives as N_TNAME:
both tests miss, the binder falls to the N_FORRANGE fallback decl,
stays untyped, and the first binop over it bails. cs twin types the
binding at scope_define (check.c N_FORRANGE) — accepts.

FIX (single site, the one the repro traces to, per grant): dealias
via the existing resolvealias(unwrapbang(it)) idiom before the kind
tests. The TUPLE-DESTRUCTURE arm carries the same unresolved tests
but is NOT in-grant (fixing the bare arm is not a no-op, so the
re-spelling clause does not apply) — FILED as task #97; currently
double-masked bounded-loud (cs louds upstream at #270-1c so the
alias-tuple-slice iterable is unconstructible on cs; ww asserttyped).

Rows (944): rangevar_alias2 (the repro, cs0/ww-reject -> 0/0 byte-id)
+ rangevar_plain_ctl (non-alias control, held throughout). 944
202/202. Corpus: five-mains ww NEUTRAL vs base on identical inputs
(checker-acceptance-only change; no alias range-for in corpus).
combined.ww regens ride along.
This commit is contained in:
2026-06-06 00:16:07 +09:00
parent 10d886906f
commit bcd948de88
4 changed files with 52 additions and 0 deletions

View File

@@ -10740,6 +10740,13 @@ fn resolvewalk(c: *checker, n: *node) void = {
// and no dot applies to a u8 binding. // and no dot applies to a u8 binding.
let et: *node = nil; let et: *node = nil;
let it: *node = exprtype(c, n.lhs, nil); let it: *node = exprtype(c, n.lhs, nil);
// #80 (F2a batch-4 c4): an alias-typed iterable
// arrives as N_TNAME — without the AST-level
// dealias the binder fell to the N_FORRANGE
// fallback decl, stayed untyped, and any binop
// over the rangevar asserttyped-bailed (cs
// accepts: its scope_define types the elem).
if (it != nil) { it = resolvealias(c, unwrapbang(it)); };
if (it != nil) { if (it != nil) {
if (it.kind == nkind.N_TSLICE) { et = it.lhs; }; if (it.kind == nkind.N_TSLICE) { et = it.lhs; };
if (it.kind == nkind.N_TARRAY) { et = it.lhs; }; if (it.kind == nkind.N_TARRAY) { et = it.lhs; };

View File

@@ -468,6 +468,13 @@ fn resolvewalk(c: *checker, n: *node) void = {
// and no dot applies to a u8 binding. // and no dot applies to a u8 binding.
let et: *node = nil; let et: *node = nil;
let it: *node = exprtype(c, n.lhs, nil); let it: *node = exprtype(c, n.lhs, nil);
// #80 (F2a batch-4 c4): an alias-typed iterable
// arrives as N_TNAME — without the AST-level
// dealias the binder fell to the N_FORRANGE
// fallback decl, stayed untyped, and any binop
// over the rangevar asserttyped-bailed (cs
// accepts: its scope_define types the elem).
if (it != nil) { it = resolvealias(c, unwrapbang(it)); };
if (it != nil) { if (it != nil) {
if (it.kind == nkind.N_TSLICE) { et = it.lhs; }; if (it.kind == nkind.N_TSLICE) { et = it.lhs; };
if (it.kind == nkind.N_TARRAY) { et = it.lhs; }; if (it.kind == nkind.N_TARRAY) { et = it.lhs; };

View File

@@ -10740,6 +10740,13 @@ fn resolvewalk(c: *checker, n: *node) void = {
// and no dot applies to a u8 binding. // and no dot applies to a u8 binding.
let et: *node = nil; let et: *node = nil;
let it: *node = exprtype(c, n.lhs, nil); let it: *node = exprtype(c, n.lhs, nil);
// #80 (F2a batch-4 c4): an alias-typed iterable
// arrives as N_TNAME — without the AST-level
// dealias the binder fell to the N_FORRANGE
// fallback decl, stayed untyped, and any binop
// over the rangevar asserttyped-bailed (cs
// accepts: its scope_define types the elem).
if (it != nil) { it = resolvealias(c, unwrapbang(it)); };
if (it != nil) { if (it != nil) {
if (it.kind == nkind.N_TSLICE) { et = it.lhs; }; if (it.kind == nkind.N_TSLICE) { et = it.lhs; };
if (it.kind == nkind.N_TARRAY) { et = it.lhs; }; if (it.kind == nkind.N_TARRAY) { et = it.lhs; };

View File

@@ -1106,6 +1106,37 @@ static const struct row rows[] = {
" return check(b);\n" " return check(b);\n"
"};\n", 0, K_RUN_CS_WWERR, "};\n", 0, K_RUN_CS_WWERR,
"unsupported address-of shape" }, /* ww: task #96 */ "unsupported address-of shape" }, /* ww: task #96 */
/* ---- F2a batch-4 c4 (#80): bare-binder N_FORRANGE over an
* alias-typed iterable — the binder type derivation read the
* scrutinee's type expr without dealiasing (N_TNAME missed the
* N_TSLICE/N_TARRAY tests), binder fell to the untyped fallback
* decl, `untyped_lit * rangevar` asserttyped-bailed on ww only
* (cs scope_define types the elem). Re-probed AFTER c1 per spec:
* still live (the chase set didn't cover this AST-keyed read).
* Tuple-destructure arm sibling FILED (task #97, double-masked). */
{ "rangevar_alias2", /* the #80 repro shape */
"package main;\n"
"type slk = []int;\n"
"export fn main() i32 = {\n"
" let a: [4]int = [10: int, 20: int, 30: int, 40: int];\n"
" let t: slk = a[2:];\n"
" if (t.len != 2) { return 1; };\n"
" if (t.cap != 2) { return 2; };\n"
" let sum: int = 0;\n"
" for (let x .. t) { sum = sum + 0 * x + 1; };\n"
" if (sum != 2) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
{ "rangevar_plain_ctl", /* non-alias control — held throughout */
"package main;\n"
"export fn main() i32 = {\n"
" let a: [4]int = [10: int, 20: int, 30: int, 40: int];\n"
" let t: []int = a[2:];\n"
" let sum: int = 0;\n"
" for (let x .. t) { sum = sum + 0 * x + 1; };\n"
" if (sum != 2) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* BOUND expected-state row (#199α + #90): untyped literal into a /* BOUND expected-state row (#199α + #90): untyped literal into a
* NESTED-tagged alias-wrapped variant. cs CHECKER loud-rejects — * NESTED-tagged alias-wrapped variant. cs CHECKER loud-rejects —
* the #199α ww-stricter no-transitive-drill rule (type.c:316-324); * the #199α ww-stricter no-transitive-drill rule (type.c:316-324);