w6c+wwstage: store struct-literal array-field init (#249 BUG A)
A struct literal initialising an array-typed field as a local
(`e{ encmap = [..] }`) silently dropped the initializer: cg_structlit_fill
(cstage) / cgstructlitfill (wwstage) had no TY_ARRAY field arm, so the
array field fell to the generic scalar tail — cgexpr the N_ARRLIT (→ AX≈0)
then store one sized word — losing every element. cstage returned 0;
wwstage emitted byte-identical wrong code. (The GLOBAL literal-init path
is unaffected: it goes through emit_struct_lit_bytes, already correct via
#129 A.3.)
Both stages now element-wise store the N_ARRLIT at base+field_off+i*esz,
reusing the proven N_LET array-init shape (cgen.c:8467 / cgenstmt.ww:1393)
for int and float elements plus its `...` repeat fill; esz routes through
the type table (rule 13). str/slice/struct/tagged ELEMENT arrays are the
N_LET path's documented multi-word gap (cgen.c:8462) — converted from the
silent drop to a LOUD rule-7 error in both stages, not left silent.
Symmetric both stages (rule 10), byte-identical .s.
The `...` repeat in a struct-literal array field is checker-unreachable
today (the field type-check rejects `[v...]` length inference — a
separate checker gap); the arm mirrors N_LET's repeat for symmetry.
Test 949_structlit_arrfield_run: +local literal-init reads (idx 0 / last
element), cstage run + cs==ww byte-id.
This commit is contained in:
@@ -2547,6 +2547,84 @@ cg_structlit_fill(Cg *c, Local **locals_p, Type *lu, Node *lit,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* #249: array-typed field initialised from an N_ARRLIT. No prior
|
||||
* arm matched, so without this the generic scalar tail below
|
||||
* would cgexpr the N_ARRLIT (→ AX≈0) and store one sized word,
|
||||
* silently DROPPING every element. Store element-wise at
|
||||
* disp+foff+i*esz, reusing the N_LET array-init shape (cgen.c:
|
||||
* 8467) for int/float elements and its `...` repeat. For non-BP
|
||||
* modes cgexpr clobbers BX, so reload the base before each store
|
||||
* (the X0/AX value reg survives the reload). str/slice/struct/
|
||||
* tagged ELEMENT arrays are the N_LET path's documented multi-
|
||||
* word gap (cgen.c:8462) — loud rule-7 error, not a silent drop. */
|
||||
if (fu && fu->kind == TY_ARRAY
|
||||
&& f->lhs && f->lhs->kind == N_ARRLIT) {
|
||||
Type *esub = fu->sub;
|
||||
Type *esubu = (esub && esub->kind == TY_NAMED)
|
||||
? esub->under : esub;
|
||||
int esz = esub ? (int)esub->size : 1;
|
||||
int al_isf32 = 0;
|
||||
int is_float_el = fld_isfloat(esub, &al_isf32);
|
||||
if (type_isstr(esub) || type_isslice(esub)
|
||||
|| (esubu && (esubu->kind == TY_STRUCT
|
||||
|| esubu->kind == TY_TAGGED)))
|
||||
fatal("cg_structlit_fill: array field '%s' has a "
|
||||
"str/slice/struct/tagged element — multi-word "
|
||||
"element store is out of #249 scope (N_LET "
|
||||
"array-init gap, cgen.c:8462)",
|
||||
f->str ? f->str : "?");
|
||||
int eop = A_MOVQ;
|
||||
if (esz == 1) eop = A_MOVB;
|
||||
else if (esz == 2) eop = A_MOVW;
|
||||
else if (esz == 4) eop = A_MOVL;
|
||||
int fmov = al_isf32 ? A_MOVSS : A_MOVSD;
|
||||
int idx = 0;
|
||||
Node *last = NULL;
|
||||
int repeat = 0;
|
||||
for (Node *e = f->lhs->list; e; e = e->next) {
|
||||
if (e->kind == N_FIELD && e->str
|
||||
&& strcmp(e->str, "...") == 0) {
|
||||
repeat = 1;
|
||||
break;
|
||||
}
|
||||
cgexpr(c, e, *locals_p);
|
||||
if (mode == DST_PTR_LOCAL)
|
||||
ins2(c, A_MOVQ, amem(D_BP, srcoff),
|
||||
areg(D_BX));
|
||||
else if (mode == DST_GLOBAL)
|
||||
ins2(c, A_LEAQ, masym(c, name),
|
||||
areg(D_BX));
|
||||
int eoff = disp + (int)foff + idx * esz;
|
||||
if (is_float_el)
|
||||
ins2(c, fmov, areg(D_X0),
|
||||
amem(base_reg, eoff));
|
||||
else
|
||||
ins2(c, eop, areg(D_AX),
|
||||
amem(base_reg, eoff));
|
||||
last = e;
|
||||
idx++;
|
||||
}
|
||||
if (repeat && last) {
|
||||
while (idx < (int)fu->alen) {
|
||||
if (mode == DST_PTR_LOCAL)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, srcoff),
|
||||
areg(D_BX));
|
||||
else if (mode == DST_GLOBAL)
|
||||
ins2(c, A_LEAQ, masym(c, name),
|
||||
areg(D_BX));
|
||||
int eoff = disp + (int)foff + idx * esz;
|
||||
if (is_float_el)
|
||||
ins2(c, fmov, areg(D_X0),
|
||||
amem(base_reg, eoff));
|
||||
else
|
||||
ins2(c, eop, areg(D_AX),
|
||||
amem(base_reg, eoff));
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
cgexpr(c, f->lhs, *locals_p);
|
||||
/* For non-BP modes, cgexpr just clobbered BX; reload it
|
||||
* before the store. */
|
||||
|
||||
@@ -19036,6 +19036,140 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitline("\n");
|
||||
};
|
||||
fi = nil;
|
||||
} else if (fi.tnode != nil
|
||||
&& fi.tnode.kind == nkind.N_TARRAY
|
||||
&& fieldnode.lhs != nil
|
||||
&& fieldnode.lhs.kind == nkind.N_ARRLIT) {
|
||||
// #249: array field from an N_ARRLIT. Without this
|
||||
// the generic tail below cgexprs the N_ARRLIT (→ AX)
|
||||
// and stores one sized word, silently DROPPING every
|
||||
// element. Store element-wise at disp+foff+i*esz,
|
||||
// mirroring the N_LET array-init path
|
||||
// (cgenstmt.ww:1393). int/float elements only;
|
||||
// str/slice/struct/tagged elements are the N_LET
|
||||
// multi-word gap — loud rule-7 error (cstage
|
||||
// cg_structlit_fill twin).
|
||||
let elemn: *node = fi.tnode.lhs;
|
||||
let isstrel: bool = isstrtype(c, elemn);
|
||||
let istagel: bool = istaggedtype(c, elemn);
|
||||
let issliceel: bool = false;
|
||||
let isstructel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TSLICE) {
|
||||
issliceel = true;
|
||||
};
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (primsize(elemn.str) == 0) {
|
||||
if (structlookup(c, elemn.str) != nil) {
|
||||
isstructel = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (isstrel || issliceel || isstructel || istagel) {
|
||||
let e1: str = "ww: struct-literal array field '";
|
||||
os.write(2, e1.ptr, e1.len: u64);
|
||||
os.write(2, fname.ptr, fname.len: u64);
|
||||
let e2: str = "' has a str/slice/struct/tagged element — multi-word element store out of #249 scope (N_LET array-init gap)\n";
|
||||
os.write(2, e2.ptr, e2.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = fieldnode.lhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (fi.tnode.rhs != nil) {
|
||||
if (fi.tnode.rhs.kind == nkind.N_INTLIT) {
|
||||
total = fi.tnode.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
fi = nil;
|
||||
} else {
|
||||
cgexpr(c, fieldnode.lhs);
|
||||
// For non-BP modes, cgexpr just clobbered
|
||||
|
||||
@@ -3743,6 +3743,140 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitline("\n");
|
||||
};
|
||||
fi = nil;
|
||||
} else if (fi.tnode != nil
|
||||
&& fi.tnode.kind == nkind.N_TARRAY
|
||||
&& fieldnode.lhs != nil
|
||||
&& fieldnode.lhs.kind == nkind.N_ARRLIT) {
|
||||
// #249: array field from an N_ARRLIT. Without this
|
||||
// the generic tail below cgexprs the N_ARRLIT (→ AX)
|
||||
// and stores one sized word, silently DROPPING every
|
||||
// element. Store element-wise at disp+foff+i*esz,
|
||||
// mirroring the N_LET array-init path
|
||||
// (cgenstmt.ww:1393). int/float elements only;
|
||||
// str/slice/struct/tagged elements are the N_LET
|
||||
// multi-word gap — loud rule-7 error (cstage
|
||||
// cg_structlit_fill twin).
|
||||
let elemn: *node = fi.tnode.lhs;
|
||||
let isstrel: bool = isstrtype(c, elemn);
|
||||
let istagel: bool = istaggedtype(c, elemn);
|
||||
let issliceel: bool = false;
|
||||
let isstructel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TSLICE) {
|
||||
issliceel = true;
|
||||
};
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (primsize(elemn.str) == 0) {
|
||||
if (structlookup(c, elemn.str) != nil) {
|
||||
isstructel = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (isstrel || issliceel || isstructel || istagel) {
|
||||
let e1: str = "ww: struct-literal array field '";
|
||||
os.write(2, e1.ptr, e1.len: u64);
|
||||
os.write(2, fname.ptr, fname.len: u64);
|
||||
let e2: str = "' has a str/slice/struct/tagged element — multi-word element store out of #249 scope (N_LET array-init gap)\n";
|
||||
os.write(2, e2.ptr, e2.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = fieldnode.lhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (fi.tnode.rhs != nil) {
|
||||
if (fi.tnode.rhs.kind == nkind.N_INTLIT) {
|
||||
total = fi.tnode.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
fi = nil;
|
||||
} else {
|
||||
cgexpr(c, fieldnode.lhs);
|
||||
// For non-BP modes, cgexpr just clobbered
|
||||
|
||||
@@ -19036,6 +19036,140 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitline("\n");
|
||||
};
|
||||
fi = nil;
|
||||
} else if (fi.tnode != nil
|
||||
&& fi.tnode.kind == nkind.N_TARRAY
|
||||
&& fieldnode.lhs != nil
|
||||
&& fieldnode.lhs.kind == nkind.N_ARRLIT) {
|
||||
// #249: array field from an N_ARRLIT. Without this
|
||||
// the generic tail below cgexprs the N_ARRLIT (→ AX)
|
||||
// and stores one sized word, silently DROPPING every
|
||||
// element. Store element-wise at disp+foff+i*esz,
|
||||
// mirroring the N_LET array-init path
|
||||
// (cgenstmt.ww:1393). int/float elements only;
|
||||
// str/slice/struct/tagged elements are the N_LET
|
||||
// multi-word gap — loud rule-7 error (cstage
|
||||
// cg_structlit_fill twin).
|
||||
let elemn: *node = fi.tnode.lhs;
|
||||
let isstrel: bool = isstrtype(c, elemn);
|
||||
let istagel: bool = istaggedtype(c, elemn);
|
||||
let issliceel: bool = false;
|
||||
let isstructel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TSLICE) {
|
||||
issliceel = true;
|
||||
};
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (primsize(elemn.str) == 0) {
|
||||
if (structlookup(c, elemn.str) != nil) {
|
||||
isstructel = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (isstrel || issliceel || isstructel || istagel) {
|
||||
let e1: str = "ww: struct-literal array field '";
|
||||
os.write(2, e1.ptr, e1.len: u64);
|
||||
os.write(2, fname.ptr, fname.len: u64);
|
||||
let e2: str = "' has a str/slice/struct/tagged element — multi-word element store out of #249 scope (N_LET array-init gap)\n";
|
||||
os.write(2, e2.ptr, e2.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = fieldnode.lhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (fi.tnode.rhs != nil) {
|
||||
if (fi.tnode.rhs.kind == nkind.N_INTLIT) {
|
||||
total = fi.tnode.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
fi = nil;
|
||||
} else {
|
||||
cgexpr(c, fieldnode.lhs);
|
||||
// For non-BP modes, cgexpr just clobbered
|
||||
|
||||
@@ -64,6 +64,33 @@ static const struct row rows[] = {
|
||||
"def G: e = e { pad = [9u8, 9u8, 9u8],"
|
||||
" encmap = [65u8, 66u8, 67u8, 68u8] };\n"
|
||||
"export fn main() i32 = { return G.encmap[2]: i32; };\n", 67 },
|
||||
/* BUG A: local struct-literal init of a [4]u8 field, read idx 0.
|
||||
* Pre-fix the array field fell to the generic scalar tail (cgexpr
|
||||
* the N_ARRLIT → AX, store one word) and silently dropped every
|
||||
* element → 0. encmap[0]='A' (65). */
|
||||
{ "local_lit_read0",
|
||||
"package main;\n"
|
||||
"type e = struct { encmap: [4]u8 };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n"
|
||||
" return g.encmap[0]: i32;\n"
|
||||
"};\n", 65 },
|
||||
/* BUG A: same init, read idx 3 — asserts the LAST element landed
|
||||
* (the pre-fix single-word store would never reach it). 'D' (68). */
|
||||
{ "local_lit_read3",
|
||||
"package main;\n"
|
||||
"type e = struct { encmap: [4]u8 };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n"
|
||||
" return g.encmap[3]: i32;\n"
|
||||
"};\n", 68 },
|
||||
/* NB: a trailing `...` repeat in a struct-LITERAL array field
|
||||
* (`encmap = [7u8...]`) is rejected by the CHECKER ("[1]u8 not
|
||||
* assignable to [4]u8") — the field type-check doesn't apply the
|
||||
* repeat-length inference that bare `let a: [N]T = [v...]` gets.
|
||||
* The cg_structlit_fill array arm mirrors the N_LET `...` handling
|
||||
* for symmetry, but that path is checker-unreachable today (separate
|
||||
* checker gap, not #249). No row exercises it. */
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user