wcc_ww/cgen: c4 tyassignableuntyped full-chase — structural alignment, zero acceptance graduations, graduations ride #90
F2a batch-2 c4, per rob's FINAL RULING (i) (banked, .ai/rob-batch2-spec.md):
ww-only — the cs twin (cmd/wcc/type.c:369-385) is already harec-shaped
since F1 9bd0d8b. Port of ref/harec/src/types.c:989-996
type_is_assignable structure: full dealias of the dst when its chased
kind is not tagged (du = tichase(dst); the STR/BOOL/NIL arms read du);
the tagged variant drill keeps the ORIGINAL p.type_ and detects a
variant's taggedness via the full chase (was one-level — a 2-level
alias-tagged variant slipped INTO the recursion); INT/FLOAT/RUNE keep
the recursive predicates on the unpeeled dst, exactly as cs.
STRUCTURAL ALIGNMENT, ZERO ACCEPTANCE GRADUATIONS, GRADUATIONS RIDE
#90: on wwstage no bool/str literal reaches this funnel today — the
checker stamps N_TRUE/N_FALSE CONCRETE bool (check.ww:2440) where cs
stamps ty_untyped_bool (check.c:1234), the bool member of the #14
N_STRLIT stamp cluster (task #90, filed this train; its metadata
carries the graduation obligations: BOTH layers, the stamp AND the
flatvariantidxt pass-2 one-level pu.under guard at :2868/#17, must
clear before the bound rows flip). The live silent-wrong this would
close — `type bb2 = bb1 = bool; let v: (void|bb2) = true; v is bb2`
runs cs 0 / ww 1, single-line asm diff (tag store MOVQ $1 vs $0) —
therefore does NOT graduate here: the row dies one layer up
(pins-follow-the-layer).
test 944 (+7 rows): untyped_hold33_pin ((void|T) untyped-int init,
the #33 tagged-dst drill HOLD) + untyped_tagdst_2lvl_hold (2-level
alias tagged dst) + untyped_str2lvl_ctl (masked twin — the shape
fallback rescues str, documents the rescue) + untyped_int2lvl_ctl +
untyped_bool1lvl_ctl all K_RUN 0/0; untyped_bool2lvl_bound90
K_RUN_CS BOUND citing #90; untyped_nestvar_bound K_BUILDERR_CS BOUND
expected-state row (#199-alpha + #90) — untyped literal into a
NESTED-tagged alias-wrapped variant: cs CHECKER loud-rejects
("not assignable", the #199-alpha ww-stricter no-transitive-drill
rule, type.c:316-324) while ww's node-keyed checker accepts and the
binary runs 0 OBSERVED post-chase; the acceptance gate is check.ww
(batch-4 aligns ww down; the row flips to loud-BOTH then; ww half
pinned via #90 metadata — the harness has no cs-reject+ww-runs
mode). Every row's cs column OBSERVED (built+run) at dispatch-SHA cs
per the ratified condition; probes at /tmp/b2/c4.
989 lib-byteid ratchet: ZERO flips (31 ID / 9 DIVERGE / 3 WWREJECT
hold exactly as pinned). Byte-id: five-mains NEUTRAL on identical
inputs vs the c3 build; cs==ww on the regenerated five; test-unit 288
green. combined.ww regens ride along.
This commit is contained in:
@@ -18990,17 +18990,26 @@ fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = {
|
||||
fn tyassignableuntyped(dst: *tinfo, want: *tinfo) bool = {
|
||||
if (dst == nil) { return false; };
|
||||
if (want == nil) { return false; };
|
||||
let du: *tinfo = dst;
|
||||
if (du.kind == tykind.TY_NAMED && du.under != nil) { du = du.under; };
|
||||
if (du.kind == tykind.TY_TAGGED) {
|
||||
// c4 (rob RE-RULE 2026-06-05): FULL chase, not the one-level unwrap
|
||||
// — harec type_is_assignable dealiases the dst transitively when it
|
||||
// is not tagged and keeps the ORIGINAL dst for the tagged variant
|
||||
// drill, taggedness detected via the full chase (ref/harec/src/
|
||||
// types.c:989-996). The one-level unwrap left a 2-level named bool
|
||||
// alias variant silently mis-tagged 0 (the str twin was masked by
|
||||
// taggedvariantindext's shape fallback). Aligns ww UP to the cs
|
||||
// twin cmd/wcc/type.c:369-385, harec-shaped since F1 9bd0d8b.
|
||||
let du: *tinfo = tichase(dst);
|
||||
if (du != nil && du.kind == tykind.TY_TAGGED) {
|
||||
// concrete→tagged drill (type.c:316-324): a NESTED tagged
|
||||
// variant compares by type_eq there — never equal to an
|
||||
// untyped source — so only non-tagged variants recurse.
|
||||
// untyped source — so only non-tagged variants recurse, on
|
||||
// the variant's ORIGINAL type; the variant's taggedness is
|
||||
// detected via the full chase (was one-level: a 2-level
|
||||
// alias-tagged variant slipped INTO the recursion, diverging
|
||||
// from cs's checker-level #199α reject — see the c4 finding).
|
||||
let p: *tparam = du.params;
|
||||
for (p != nil) {
|
||||
let pu: *tinfo = p.type_;
|
||||
if (pu != nil && pu.kind == tykind.TY_NAMED
|
||||
&& pu.under != nil) { pu = pu.under; };
|
||||
let pu: *tinfo = tichase(p.type_);
|
||||
let nestedtagged: bool = false;
|
||||
if (pu != nil) {
|
||||
if (pu.kind == tykind.TY_TAGGED) { nestedtagged = true; };
|
||||
@@ -19012,30 +19021,25 @@ fn tyassignableuntyped(dst: *tinfo, want: *tinfo) bool = {
|
||||
};
|
||||
return false;
|
||||
};
|
||||
// type.c:357-369 — the per-kind holds checks run on the UNPEELED
|
||||
// dst: typeisnum/typeisfloat/typeisint self-recurse TY_NAMED like
|
||||
// their cstage twins; STR/BOOL spell out the one-level unwrap.
|
||||
// type.c:369-385 — INT/FLOAT/RUNE run on the UNPEELED dst exactly
|
||||
// like cs (typeisnum/typeisfloat/typeisint self-recurse TY_NAMED);
|
||||
// STR/BOOL/NIL read the chased du like cs reads its chased du.
|
||||
if (want.kind == tykind.TY_UNTYPED_INT) { return typeisnum(dst); };
|
||||
if (want.kind == tykind.TY_UNTYPED_FLOAT) { return typeisfloat(dst); };
|
||||
if (want.kind == tykind.TY_UNTYPED_STR) {
|
||||
if (dst.kind == tykind.TY_STR) { return true; };
|
||||
if (dst.kind == tykind.TY_NAMED && dst.under != nil) {
|
||||
return dst.under.kind == tykind.TY_STR;
|
||||
};
|
||||
return false;
|
||||
if (du == nil) { return false; };
|
||||
return du.kind == tykind.TY_STR;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_RUNE) {
|
||||
if (typeisint(dst)) { return true; };
|
||||
return dst.kind == tykind.TY_RUNE;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_BOOL) {
|
||||
if (dst.kind == tykind.TY_BOOL) { return true; };
|
||||
if (dst.kind == tykind.TY_NAMED && dst.under != nil) {
|
||||
return dst.under.kind == tykind.TY_BOOL;
|
||||
};
|
||||
return false;
|
||||
if (du == nil) { return false; };
|
||||
return du.kind == tykind.TY_BOOL;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_NIL) {
|
||||
if (du == nil) { return false; };
|
||||
if (du.kind == tykind.TY_PTR) { return true; };
|
||||
if (du.kind == tykind.TY_SLICE) { return true; };
|
||||
if (du.kind == tykind.TY_CHAN) { return true; };
|
||||
|
||||
@@ -2918,17 +2918,26 @@ fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = {
|
||||
fn tyassignableuntyped(dst: *tinfo, want: *tinfo) bool = {
|
||||
if (dst == nil) { return false; };
|
||||
if (want == nil) { return false; };
|
||||
let du: *tinfo = dst;
|
||||
if (du.kind == tykind.TY_NAMED && du.under != nil) { du = du.under; };
|
||||
if (du.kind == tykind.TY_TAGGED) {
|
||||
// c4 (rob RE-RULE 2026-06-05): FULL chase, not the one-level unwrap
|
||||
// — harec type_is_assignable dealiases the dst transitively when it
|
||||
// is not tagged and keeps the ORIGINAL dst for the tagged variant
|
||||
// drill, taggedness detected via the full chase (ref/harec/src/
|
||||
// types.c:989-996). The one-level unwrap left a 2-level named bool
|
||||
// alias variant silently mis-tagged 0 (the str twin was masked by
|
||||
// taggedvariantindext's shape fallback). Aligns ww UP to the cs
|
||||
// twin cmd/wcc/type.c:369-385, harec-shaped since F1 9bd0d8b.
|
||||
let du: *tinfo = tichase(dst);
|
||||
if (du != nil && du.kind == tykind.TY_TAGGED) {
|
||||
// concrete→tagged drill (type.c:316-324): a NESTED tagged
|
||||
// variant compares by type_eq there — never equal to an
|
||||
// untyped source — so only non-tagged variants recurse.
|
||||
// untyped source — so only non-tagged variants recurse, on
|
||||
// the variant's ORIGINAL type; the variant's taggedness is
|
||||
// detected via the full chase (was one-level: a 2-level
|
||||
// alias-tagged variant slipped INTO the recursion, diverging
|
||||
// from cs's checker-level #199α reject — see the c4 finding).
|
||||
let p: *tparam = du.params;
|
||||
for (p != nil) {
|
||||
let pu: *tinfo = p.type_;
|
||||
if (pu != nil && pu.kind == tykind.TY_NAMED
|
||||
&& pu.under != nil) { pu = pu.under; };
|
||||
let pu: *tinfo = tichase(p.type_);
|
||||
let nestedtagged: bool = false;
|
||||
if (pu != nil) {
|
||||
if (pu.kind == tykind.TY_TAGGED) { nestedtagged = true; };
|
||||
@@ -2940,30 +2949,25 @@ fn tyassignableuntyped(dst: *tinfo, want: *tinfo) bool = {
|
||||
};
|
||||
return false;
|
||||
};
|
||||
// type.c:357-369 — the per-kind holds checks run on the UNPEELED
|
||||
// dst: typeisnum/typeisfloat/typeisint self-recurse TY_NAMED like
|
||||
// their cstage twins; STR/BOOL spell out the one-level unwrap.
|
||||
// type.c:369-385 — INT/FLOAT/RUNE run on the UNPEELED dst exactly
|
||||
// like cs (typeisnum/typeisfloat/typeisint self-recurse TY_NAMED);
|
||||
// STR/BOOL/NIL read the chased du like cs reads its chased du.
|
||||
if (want.kind == tykind.TY_UNTYPED_INT) { return typeisnum(dst); };
|
||||
if (want.kind == tykind.TY_UNTYPED_FLOAT) { return typeisfloat(dst); };
|
||||
if (want.kind == tykind.TY_UNTYPED_STR) {
|
||||
if (dst.kind == tykind.TY_STR) { return true; };
|
||||
if (dst.kind == tykind.TY_NAMED && dst.under != nil) {
|
||||
return dst.under.kind == tykind.TY_STR;
|
||||
};
|
||||
return false;
|
||||
if (du == nil) { return false; };
|
||||
return du.kind == tykind.TY_STR;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_RUNE) {
|
||||
if (typeisint(dst)) { return true; };
|
||||
return dst.kind == tykind.TY_RUNE;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_BOOL) {
|
||||
if (dst.kind == tykind.TY_BOOL) { return true; };
|
||||
if (dst.kind == tykind.TY_NAMED && dst.under != nil) {
|
||||
return dst.under.kind == tykind.TY_BOOL;
|
||||
};
|
||||
return false;
|
||||
if (du == nil) { return false; };
|
||||
return du.kind == tykind.TY_BOOL;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_NIL) {
|
||||
if (du == nil) { return false; };
|
||||
if (du.kind == tykind.TY_PTR) { return true; };
|
||||
if (du.kind == tykind.TY_SLICE) { return true; };
|
||||
if (du.kind == tykind.TY_CHAN) { return true; };
|
||||
|
||||
@@ -18990,17 +18990,26 @@ fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = {
|
||||
fn tyassignableuntyped(dst: *tinfo, want: *tinfo) bool = {
|
||||
if (dst == nil) { return false; };
|
||||
if (want == nil) { return false; };
|
||||
let du: *tinfo = dst;
|
||||
if (du.kind == tykind.TY_NAMED && du.under != nil) { du = du.under; };
|
||||
if (du.kind == tykind.TY_TAGGED) {
|
||||
// c4 (rob RE-RULE 2026-06-05): FULL chase, not the one-level unwrap
|
||||
// — harec type_is_assignable dealiases the dst transitively when it
|
||||
// is not tagged and keeps the ORIGINAL dst for the tagged variant
|
||||
// drill, taggedness detected via the full chase (ref/harec/src/
|
||||
// types.c:989-996). The one-level unwrap left a 2-level named bool
|
||||
// alias variant silently mis-tagged 0 (the str twin was masked by
|
||||
// taggedvariantindext's shape fallback). Aligns ww UP to the cs
|
||||
// twin cmd/wcc/type.c:369-385, harec-shaped since F1 9bd0d8b.
|
||||
let du: *tinfo = tichase(dst);
|
||||
if (du != nil && du.kind == tykind.TY_TAGGED) {
|
||||
// concrete→tagged drill (type.c:316-324): a NESTED tagged
|
||||
// variant compares by type_eq there — never equal to an
|
||||
// untyped source — so only non-tagged variants recurse.
|
||||
// untyped source — so only non-tagged variants recurse, on
|
||||
// the variant's ORIGINAL type; the variant's taggedness is
|
||||
// detected via the full chase (was one-level: a 2-level
|
||||
// alias-tagged variant slipped INTO the recursion, diverging
|
||||
// from cs's checker-level #199α reject — see the c4 finding).
|
||||
let p: *tparam = du.params;
|
||||
for (p != nil) {
|
||||
let pu: *tinfo = p.type_;
|
||||
if (pu != nil && pu.kind == tykind.TY_NAMED
|
||||
&& pu.under != nil) { pu = pu.under; };
|
||||
let pu: *tinfo = tichase(p.type_);
|
||||
let nestedtagged: bool = false;
|
||||
if (pu != nil) {
|
||||
if (pu.kind == tykind.TY_TAGGED) { nestedtagged = true; };
|
||||
@@ -19012,30 +19021,25 @@ fn tyassignableuntyped(dst: *tinfo, want: *tinfo) bool = {
|
||||
};
|
||||
return false;
|
||||
};
|
||||
// type.c:357-369 — the per-kind holds checks run on the UNPEELED
|
||||
// dst: typeisnum/typeisfloat/typeisint self-recurse TY_NAMED like
|
||||
// their cstage twins; STR/BOOL spell out the one-level unwrap.
|
||||
// type.c:369-385 — INT/FLOAT/RUNE run on the UNPEELED dst exactly
|
||||
// like cs (typeisnum/typeisfloat/typeisint self-recurse TY_NAMED);
|
||||
// STR/BOOL/NIL read the chased du like cs reads its chased du.
|
||||
if (want.kind == tykind.TY_UNTYPED_INT) { return typeisnum(dst); };
|
||||
if (want.kind == tykind.TY_UNTYPED_FLOAT) { return typeisfloat(dst); };
|
||||
if (want.kind == tykind.TY_UNTYPED_STR) {
|
||||
if (dst.kind == tykind.TY_STR) { return true; };
|
||||
if (dst.kind == tykind.TY_NAMED && dst.under != nil) {
|
||||
return dst.under.kind == tykind.TY_STR;
|
||||
};
|
||||
return false;
|
||||
if (du == nil) { return false; };
|
||||
return du.kind == tykind.TY_STR;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_RUNE) {
|
||||
if (typeisint(dst)) { return true; };
|
||||
return dst.kind == tykind.TY_RUNE;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_BOOL) {
|
||||
if (dst.kind == tykind.TY_BOOL) { return true; };
|
||||
if (dst.kind == tykind.TY_NAMED && dst.under != nil) {
|
||||
return dst.under.kind == tykind.TY_BOOL;
|
||||
};
|
||||
return false;
|
||||
if (du == nil) { return false; };
|
||||
return du.kind == tykind.TY_BOOL;
|
||||
};
|
||||
if (want.kind == tykind.TY_UNTYPED_NIL) {
|
||||
if (du == nil) { return false; };
|
||||
if (du.kind == tykind.TY_PTR) { return true; };
|
||||
if (du.kind == tykind.TY_SLICE) { return true; };
|
||||
if (du.kind == tykind.TY_CHAN) { return true; };
|
||||
|
||||
Reference in New Issue
Block a user