w6c/cgen: #78 alias-NAMED global decls — let_* + DATA-emit entry chase (g-fold G1)
cs half of the #77+#78 fused g-fold train (rob spec .ai/rob-gfold-spec.md + ENROLLMENT RULING 2026-06-05). NEITHER COMMIT FFs ALONE — G2 (wwstage emit dispatch, #77) completes the train; until G2 lands, ww alias-global ARRAY rows remain loud link-ERR by design (documented below). Root: the let_* helper family was single-peel (`u = (t->kind==TY_NAMED) ? t->under : t`) — a 2-level alias chain (or ONE user alias over a named struct) left u TY_NAMED, so let_collect never registered the global, no DATA was emitted, and the let_islet-gated load paths fell through to the frame-local path at offset 0: a silent saved-BP read (probe-verified: cs emitted zero DATAW and zero main.g references for a2/st1/t2/sl2). Converted to type_chase_named (6 helpers, per the enrollment ruling — probes forced let_isstr/let_isslice in beyond the spec's enumerated 4; non-severable, ruling banked in the spec file): let_emit_size (:1164) consumers :1408 let_collect gate, :14889 emit_lets, :15196 let_pre_intern str-leg — all top-level d->type let_isstr (:1208) consumer :3894 N_IDENT global load gate let_isslice (:1218) consumers :3894, :14987 emit_lets slice arm, :15080 emit_defs loud-stop let_isstruct (:1229) consumers :1432 def registry, :14923 8B-scalar short-circuit gate, :14996/:15062 struct emit arms let_isarray (:1240) consumers :1445 def registry, :14923, :14975/:14997/:15071 array emit arms let_isfloat (:1251) consumers :1507 def addressability, :3908 N_IDENT float load (non-local branch only — locals take the off!=0 branch at :3793), :14891/:15052 float emit All consumers sit on top-level-decl or non-local-ident paths; no local consumer exists. Corpus census: zero >=2-NAMED-layer global decl types anywhere in lib/selfhost/cmd (all named globals are depth-1: io.vtable, memio.stream, errno, duration, floatinfo, encoding, ...) — conversion is identity on the whole existing-green corpus; full byte-id invariant holds (test-unit 287/287, sizelint clean). Condition-3 members (ruling: "own inline peel on the routed path = same family, enroll if it fixes at the same chase" — verified: every enrolled probe row graduates at this chase, none elsewhere): the routed-to DATA emitters re-peeled at entry and return-0'd into the silent skip path. Converted the OUTER-type entry resolution only: emit_struct_lit_bytes :14238, emit_struct_data :14363, emit_array_lit_bytes :14401, emit_strarray_data :14618, emit_array_data :14791, emit_slice_data :14830, let_pre_intern array-leg :15131 ELEMENT-type peels in those helpers are untouched (different axis, out of this fold). type_unwrap itself is NOT converted (#85, explicit OUT); its two remaining consumers (:14711/:14902) are tuple-arm-only, behind the checker reject filed as #86. Probe matrix (banked /tmp/implG_probes.md + /tmp/implG/): 34 rows, both stages. Post-G1: every cs alias-global row runs 0 — a2/a2o (the #78 silent saved-BP rows), st1/st2 (silent SEGV at one user alias level), stlit/t2/sl2/d_a2/d_st2/tsa2 (silent-wrong), s2/s2o/f2/f2s/d_f2 (loud), u1/tsa1/a1* (held green). All ww-green rows byte-id YES. ww array rows stay loud link-ERR until G2 (`w6l: undefined reference to main.g`). Controls + holds (plain globals, alias-ELEMENT el1, alias-slice sl1) unchanged. OUT, filed: #86 (named-tuple global init, checker), #87 (plain tagged global, cs silent vs ww loud — not alias-family).
This commit is contained in:
@@ -1154,12 +1154,17 @@ static DefAny *defall;
|
||||
* supported as a writable global yet. Tagged unions are deferred.
|
||||
* enums route through their storage type.
|
||||
* Keep this tight — extending it requires the matching load/store
|
||||
* code below. */
|
||||
* code below.
|
||||
* The let_* family (this + the five kind-predicates below) chases the
|
||||
* alias chain transitively (#77/#78 g-fold): a single peel left a
|
||||
* 2-level-alias global TY_NAMED → size 0 / predicate false → never
|
||||
* registered, no DATA, and reads fell to the frame-local path at
|
||||
* offset 0 — silently reading saved BP. */
|
||||
static int
|
||||
let_emit_size(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL) return 0;
|
||||
switch (u->kind) {
|
||||
case TY_BOOL: case TY_RUNE:
|
||||
@@ -1203,7 +1208,7 @@ static int
|
||||
let_isstr(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
return u && u->kind == TY_STR;
|
||||
}
|
||||
|
||||
@@ -1213,7 +1218,7 @@ static int
|
||||
let_isslice(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
return u && u->kind == TY_SLICE;
|
||||
}
|
||||
|
||||
@@ -1224,7 +1229,7 @@ static int
|
||||
let_isstruct(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
return u && u->kind == TY_STRUCT;
|
||||
}
|
||||
|
||||
@@ -1235,7 +1240,7 @@ static int
|
||||
let_isarray(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
return u && u->kind == TY_ARRAY;
|
||||
}
|
||||
|
||||
@@ -1246,7 +1251,7 @@ static int
|
||||
let_isfloat(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
return u && (u->kind == TY_F32 || u->kind == TY_F64);
|
||||
}
|
||||
|
||||
@@ -14232,7 +14237,11 @@ static int emit_array_lit_bytes(FILE *out, Cg *c, Type *t, Node *rhs,
|
||||
static int
|
||||
emit_struct_lit_bytes(FILE *out, Cg *c, Type *t, Node *rhs, u64 base)
|
||||
{
|
||||
Type *u = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||
/* Transitive entry chase (#77/#78 g-fold, condition-3 member): the
|
||||
* single peel return-0'd on a 2-level-alias struct and the caller's
|
||||
* skip-path emitted NO DATA for a registered global — undefined
|
||||
* reference where pre-G1 it was a silent frame-local read. */
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_STRUCT) return 0;
|
||||
u64 pos = base;
|
||||
for (Tfield *f = u->fields; f != NULL; f = f->next) {
|
||||
@@ -14354,7 +14363,7 @@ static int
|
||||
emit_struct_data(FILE *out, Cg *c, const char *directive,
|
||||
const char *name, const char *module, Type *t, Node *rhs)
|
||||
{
|
||||
Type *u = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_STRUCT) return 0;
|
||||
fprintf(out, "%s %s(SB),\"", directive,
|
||||
mod_mangle_value(c, name, module));
|
||||
@@ -14391,7 +14400,7 @@ emit_struct_data(FILE *out, Cg *c, const char *directive,
|
||||
static int
|
||||
emit_array_lit_bytes(FILE *out, Cg *c, Type *t, Node *rhs, int emit_phase)
|
||||
{
|
||||
Type *u = type_unwrap(t);
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_ARRAY) return 0;
|
||||
Type *etype = u->sub;
|
||||
Type *eu = (etype && etype->kind == TY_NAMED) ? etype->under : etype;
|
||||
@@ -14609,7 +14618,7 @@ static int
|
||||
emit_strarray_data(FILE *out, Cg *c, const char *directive,
|
||||
const char *name, const char *module, Type *t, Node *rhs)
|
||||
{
|
||||
Type *u = type_unwrap(t);
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_ARRAY) return 0;
|
||||
Type *etype = u->sub;
|
||||
Type *eu = (etype && etype->kind == TY_NAMED) ? etype->under : etype;
|
||||
@@ -14783,7 +14792,7 @@ static int
|
||||
emit_array_data(FILE *out, Cg *c, const char *directive,
|
||||
const char *name, const char *module, Type *t, Node *rhs)
|
||||
{
|
||||
Type *u = type_unwrap(t);
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_ARRAY) return 0;
|
||||
/* str-element arrays carry per-element ptr relocations — handled
|
||||
* by the dedicated DATAW+DATAR helper (#18). */
|
||||
@@ -14818,7 +14827,7 @@ static int
|
||||
emit_slice_data(FILE *out, Cg *c, const char *directive, const char *name,
|
||||
const char *module, Type *t, Node *rhs)
|
||||
{
|
||||
Type *u = type_unwrap(t);
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_SLICE) return 0;
|
||||
if (rhs == NULL || rhs->kind != N_ARRLIT) return 0;
|
||||
if (strcmp(directive, "DATAW") != 0)
|
||||
@@ -15118,8 +15127,11 @@ let_pre_intern(Cg *c, Node *file)
|
||||
/* #18: `let xs: [N]str = […];` — pre-intern each element's
|
||||
* strlit in element order (then repeat-fill) so emit_strarray_
|
||||
* data's DATAR rows find an _S_ rodata row. Must match that
|
||||
* helper's interning order exactly to keep labels stable. */
|
||||
Type *u = type_unwrap(d->type);
|
||||
* helper's interning order exactly to keep labels stable.
|
||||
* Chase transitively (#77/#78 g-fold): emit_strarray_data now
|
||||
* reaches 2-level-alias [N]str globals; a single peel here
|
||||
* would intern their labels in emit order, not decl order. */
|
||||
Type *u = type_chase_named(d->type);
|
||||
if (u != NULL && u->kind == TY_ARRAY
|
||||
&& r != NULL && r->kind == N_ARRLIT) {
|
||||
Type *eu = (u->sub && u->sub->kind == TY_NAMED)
|
||||
|
||||
Reference in New Issue
Block a user