diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 1aeb4691..c81f312d 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -921,13 +921,18 @@ cg_tag_for_variant(Type *t, Type *vt) int found = -1, n = 0; idx = 0; for (Tparam *p = t->params; p; p = p->next, idx++) { - /* One-level NAMED unwrap: a chained ptr-alias variant - * (type a=*X; type b=a) isn't reached here, so it would - * silently mis-tag — unexercised (zero in corpus), see - * task #17. */ + /* Full chase (F2a batch-4 c2): the old one-level + * unwrap missed a chained ptr-alias variant + * (type a=*X; type b=a) — every pass fell through + * and the widen defaulted to tag 0, SILENT. The + * TY_NAMED gate keeps bare variants in pass-1's + * exact domain; the >=2-candidate hard-error below + * guards the CHASED match set. ww twin + * flatvariantidxt fused in this commit (probe: + * both-wrong-identical pre-fix). */ Type *pu = p->type; - if (pu && pu->kind == TY_NAMED && pu->under - && type_eq(pu->under, vt)) { + if (pu && pu->kind == TY_NAMED + && type_eq(type_chase_named(pu), vt)) { if (found < 0) found = idx; n++; } diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index edc8907b..628882ca 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -18973,13 +18973,18 @@ fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = { let found: i32 = -1; let n: i32 = 0; for (q != nil) { - // One-level NAMED unwrap: a chained ptr-alias variant - // (type a=*X; type b=a) isn't reached here, so it would - // silently mis-tag — unexercised (zero in corpus), see - // task #17. + // Full chase (F2a batch-4 c2): the old one-level + // unwrap missed a chained ptr-alias variant + // (type a=*X; type b=a) — every pass fell through + // and the widen defaulted to tag 0, SILENT. The + // TY_NAMED gate keeps bare variants in pass-1's + // exact domain; drew's >=2-candidate hard-error + // below now guards the CHASED match set. cs twin + // cg_tag_for_variant fused in this commit (probe: + // both-wrong-identical pre-fix). let pu: *tinfo = q.type_; if (pu != nil && pu.kind == tykind.TY_NAMED - && pu.under != nil && typeeq(pu.under, want)) { + && typeeq(tichase(pu), want)) { if (found < 0) { found = qi; }; n += 1; }; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index a75428e6..93b4ffd4 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -2898,13 +2898,18 @@ fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = { let found: i32 = -1; let n: i32 = 0; for (q != nil) { - // One-level NAMED unwrap: a chained ptr-alias variant - // (type a=*X; type b=a) isn't reached here, so it would - // silently mis-tag — unexercised (zero in corpus), see - // task #17. + // Full chase (F2a batch-4 c2): the old one-level + // unwrap missed a chained ptr-alias variant + // (type a=*X; type b=a) — every pass fell through + // and the widen defaulted to tag 0, SILENT. The + // TY_NAMED gate keeps bare variants in pass-1's + // exact domain; drew's >=2-candidate hard-error + // below now guards the CHASED match set. cs twin + // cg_tag_for_variant fused in this commit (probe: + // both-wrong-identical pre-fix). let pu: *tinfo = q.type_; if (pu != nil && pu.kind == tykind.TY_NAMED - && pu.under != nil && typeeq(pu.under, want)) { + && typeeq(tichase(pu), want)) { if (found < 0) { found = qi; }; n += 1; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index c7263664..a9bd2796 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -18973,13 +18973,18 @@ fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = { let found: i32 = -1; let n: i32 = 0; for (q != nil) { - // One-level NAMED unwrap: a chained ptr-alias variant - // (type a=*X; type b=a) isn't reached here, so it would - // silently mis-tag — unexercised (zero in corpus), see - // task #17. + // Full chase (F2a batch-4 c2): the old one-level + // unwrap missed a chained ptr-alias variant + // (type a=*X; type b=a) — every pass fell through + // and the widen defaulted to tag 0, SILENT. The + // TY_NAMED gate keeps bare variants in pass-1's + // exact domain; drew's >=2-candidate hard-error + // below now guards the CHASED match set. cs twin + // cg_tag_for_variant fused in this commit (probe: + // both-wrong-identical pre-fix). let pu: *tinfo = q.type_; if (pu != nil && pu.kind == tykind.TY_NAMED - && pu.under != nil && typeeq(pu.under, want)) { + && typeeq(tichase(pu), want)) { if (found < 0) { found = qi; }; n += 1; }; diff --git a/test/wcc/944_alias_accept_run.c b/test/wcc/944_alias_accept_run.c index c73ecd5e..4ecfd5bd 100644 --- a/test/wcc/944_alias_accept_run.c +++ b/test/wcc/944_alias_accept_run.c @@ -103,6 +103,8 @@ slurp_eq(const char *a, const char *b) #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) */ +#define K_RUN_NOID 4 /* build+run BOTH, exit==want, byte-id + * SKIPPED — cite the blocking task */ struct row { const char *label; const char *src; int want; int kind; const char *experr; }; @@ -927,13 +929,12 @@ static const struct row rows[] = { " if (!(v is ba1)) { return 1; };\n" " return 0;\n" "};\n", 0, K_RUN, NULL }, - /* BOUND row (task #90): ww stamps N_TRUE CONCRETE bool - * (check.ww:2440) vs cs untyped_bool (check.c:1234), so the bool - * literal never reaches the c4-chased untyped funnel on ww — it - * dies at flatvariantidxt pass-2's one-level pu.under guard - * (cgenutil.ww:2868, the #17 site): SILENT tag 0, ww runs exit 1 - * where cs runs 0. Flip to K_RUN when #90 clears BOTH layers - * (stamp + fallback peel). */ + /* GRADUATED at F2a batch-4 c2 (route-trace case (b)): the + * pass-2 full chase alone took this 0/0 byte-id — ww's CONCRETE + * bool (the #90 stamp divergence, still open at c2) now matches + * the 2-level alias variant through the chased structural + * fallback, converging with cs's untyped-funnel route on the + * same tag. #90's stamp flip pins its own rows (c5). */ { "untyped_bool2lvl_bound90", "package main;\n" "type bb1 = bool;\n" @@ -942,7 +943,81 @@ static const struct row rows[] = { " let v: (void | bb2) = true;\n" " if (!(v is bb2)) { return 1; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ww: task #90 */ + "};\n", 0, K_RUN, NULL }, + /* ---- F2a batch-4 c2: flatvariantidxt/cg_tag_for_variant pass-2 + * FULL CHASE, fused both stages (probe: v2_alias2 was exit 1/1 + * BOTH-WRONG-IDENTICAL pre-fix — the one-level pu unwrap missed + * every pass on a 2-level alias variant, tag 0 silent). v2_ctrl + * pins the #15 io-vtable consumer (1-level, held throughout); + * v2_ambig pins drew's >=2-candidate hard-error applied to the + * CHASED match set. */ + { "v2_ctrl", /* bare *T into 1-LEVEL named-ptr variant (io shape) */ + "package main;\n" + "type pc = *i64;\n" + "export fn main() i32 = {\n" + " let x: i64 = 7;\n" + " let v: (void | pc) = &x;\n" + " if (v is pc) { return 0; };\n" + " return 1;\n" + "};\n", 0, K_RUN, NULL }, + { "v2_alias2", /* bare *T into 2-LEVEL alias variant */ + "package main;\n" + "type pa = *i64;\n" + "type pb = pa;\n" + "export fn main() i32 = {\n" + " let x: i64 = 7;\n" + " let v: (void | pb) = &x;\n" + " if (v is pb) { return 0; };\n" + " return 1;\n" + "};\n", 0, K_RUN, NULL }, + { "v2_struct2", /* bare (anonymous-let) struct into 2-level alias + * variant. NOID: asm diverges on 3 pre-existing + * cglet zero-fill lines (cs XORQ+2 stores, ww none + * — task #81 class, runtime-correct both, ORTHOGONAL + * to the variant tag). Flip to K_RUN when the + * zero-fill divergence closes. The adjacent + * NAMED-source shape is task #95 (ken b4-oracle), + * out of this fix's set. */ + "package main;\n" + "type sa = struct { a: i64, };\n" + "type sb = sa;\n" + "export fn main() i32 = {\n" + " let s: struct { a: i64, } = sa{a=7};\n" + " let v: (void | sb) = s;\n" + " if (v is sb) { return 0; };\n" + " return 1;\n" + "};\n", 0, K_RUN_NOID, NULL }, + { "v2_ambig", /* bare source matching >=2 NAMED variants stays a + * hard error on the CHASED set (drew's proviso) */ + "package main;\n" + "type p1 = *i64;\n" + "type p2 = *i64;\n" + "export fn main() i32 = {\n" + " let x: i64 = 7;\n" + " let v: (void | p1 | p2) = &x;\n" + " if (v is p1) { return 0; };\n" + " return 1;\n" + "};\n", 0, K_BUILDERR, + "bare source structurally matches >=2 NAMED variants" }, + /* The RATIFIED acceptance-narrowing pin (FLAG-P1, kb4_v2_ambig2): + * 2-LEVEL twin variants. Pre-c2 the chase-less fallback matched + * NEITHER twin — the build ACCEPTED on both stages and ran a + * silent mis-tag (byte-identical, gate-blind). The chased set + * sees both twins structurally -> drew's >=2-candidate + * hard-error, BOTH stages. */ + { "v2_ambig2", + "package main;\n" + "type q1 = *i64;\n" + "type p1 = q1;\n" + "type q2 = *i64;\n" + "type p2 = q2;\n" + "export fn main() i32 = {\n" + " let x: i64 = 7;\n" + " let v: (void | p1 | p2) = &x;\n" + " if (v is p1) { return 0; };\n" + " return 1;\n" + "};\n", 0, K_BUILDERR, + "bare source structurally matches >=2 NAMED variants" }, /* BOUND expected-state row (#199α + #90): untyped literal into a * NESTED-tagged alias-wrapped variant. cs CHECKER loud-rejects — * the #199α ww-stricter no-transitive-drill rule (type.c:316-324); @@ -1131,7 +1206,7 @@ main(void) for (int i = 0; i < n; i++) { if (rows[i].kind == K_RUN_CS || rows[i].kind == K_BUILDERR_CS) - continue; + continue; /* K_RUN_NOID: ww half RUNS */ total++; if (run_driver(wdrv, &rows[i], i) != 0) fail++; }