wcc/check: #6 stamp inferred-type array global so wwstage compiles it (was asserttyped exit 1)
An inferred-type array global -- let xs = [1,2,3]; -- hard-failed wwstage with 'asserttyped: int' exit 1, while cstage compiled+ran it. The array-twin of the inferred-global family (#135 inferred-float, #150-B inferred-Sym-repoint). exprtype's N_ARRLIT arm synthesizes the array type for an unannotated literal but left two synthesized child nodes unstamped: the count literal (asserttyped trips on it -> the loud failure) and the element TNAME (cgen then drops a non-scalar element's header load -> the silent miscompile that merely accepting on alone would introduce: an inferred str-array's xs[1].len read 24 not 3). Both are now stamped at the synthesis site: cn.type_ (asserttyped facet) and elt.type_ (cgen facet). Inferred int / u8 / str / struct / multi-dim array globals + locals + args now compile byte-identically to the explicit-typed form (== cstage). cstage unchanged (w6c md5 unchanged); selfhost has no inferred array globals so byte-id 990-997 8/8, no lib pin flips. test/wcc/833.
This commit is contained in:
@@ -13651,9 +13651,29 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
// check.c:1859 empty-fallback ty_int (#103). Was "i32".
|
||||
if (elt == nil) { elt = mktname(c, "int"); };
|
||||
let arr: *node = newnode(nkind.N_TARRAY, "", 0, 0);
|
||||
// #6(niche): stamp the SYNTHESIZED element TNAME so the inferred
|
||||
// array's cgen is IDENTICAL to an explicit [N]T's (whose element is
|
||||
// resolvewalk-stamped). For a scalar element (int/u8) cgen's
|
||||
// fallback reads correctly with a nil elt.type_ (byte-id either
|
||||
// way), but a multi-word element (str, 24B) needs the resolved
|
||||
// element tinfo to emit the 3-word header element load — without it
|
||||
// cgen drops to the 8B-scalar path and `xs[i].len` reads the slot
|
||||
// stride, not the length (silent cs!=ww). Idempotent: elt may be a
|
||||
// real exprtype result whose type_ is already set.
|
||||
if (elt.type_ == nil) { elt.type_ = tinfofornode(c, elt): *void; };
|
||||
arr.lhs = elt;
|
||||
let cn: *node = newnode(nkind.N_INTLIT, "", 0, 0);
|
||||
cn.uval = count;
|
||||
// #6(niche): stamp the SYNTHESIZED count literal. When this arr is
|
||||
// planted on an inferred array global's n.lhs (the array twin of
|
||||
// #135/#150-B), asserttyped walks arr.rhs (this N_INTLIT, an expr
|
||||
// node) and trips `asserttyped: int` — an explicit [N]T's count is
|
||||
// resolvewalk-stamped, the synthesized inferred one wasn't. The
|
||||
// element TNAME (arr.lhs) needs no stamp: N_TNAME is not an
|
||||
// asserttyped expr kind. tinfofornode only resolves type-kind
|
||||
// nodes, so type the count off a fresh `int` TNAME; cgen reads
|
||||
// arr.rhs.uval, so this stamp is byte-id-inert.
|
||||
cn.type_ = tinfofornode(c, mktname(c, "int")): *void;
|
||||
arr.rhs = cn;
|
||||
e.type_ = tinfofornode(c, arr): *void;
|
||||
// #103: stamp the synthesized array NODE too. checkletassign
|
||||
|
||||
Reference in New Issue
Block a user