wwstage: accept module-level const/let slice-from-arrlit (#28)
wwstage rejected a module-level `const/let []T = [arrlit]` global with "let: not assignable"; cstage accepts (textbook Hare, ref/hare/path/stack.ha:30). The arrlit->slice admission in checkletassign was gated local-only; lift it to module scope too, aligning wwstage UP to cstage's arrlit_init_fits (check.c:3406-3409, slice arm 519-520). cstage unchanged. Two guards the un-gating requires: the n.rhs.lhs=arr stash stays local-only (a module decl keeps its raw N_ARRLIT for DATA emit, so stashing would leave an untyped count node for the pass-3 asserttyped walker); and tuple-element slice globals are excluded at module scope, because the synthesis delegates element checks to isassignable which lacks a strict tuple arm (#38) -- a [](str,*fn) table would over-accept a sig-mismatched &fn that cstage's strict type_assignable rejects (#124) -- so they stay on the existing typeeqast path. Closes two divergences 944_alias_emit_b7 pinned: Group A (cstage-runs/ww-rejects) migrates to test/lang/slice_global_arg_test.ww (promoted from _runonly, now cs==ww byte-id); Group B converges to a shared emit_slice_data reject with the identical diagnostic.
This commit is contained in:
@@ -5975,16 +5975,39 @@ fn checkletassign(c: *checker, n: *syntax.node) void = {
|
||||
&& n.rhs.kind == syntax.nkind.N_TUPLE) {
|
||||
checktuplearrfits(c, llhs, n.rhs);
|
||||
};
|
||||
// #25/#31: an array literal initialising a SLICE local. Re-stamp the
|
||||
// #25/#31: an array literal initialising a SLICE binding. Re-stamp the
|
||||
// literal as [count]T (the slice element) so the #258 borrow's exact-
|
||||
// element typeeq holds and the cgen N_SLICE-over-N_ARRLIT arm reads the
|
||||
// declared element width. Run the same per-element coercion + range-
|
||||
// check the array path runs (checkarrlitfits against a synthesized
|
||||
// [count]T), then drive isassignable + the borrow off [count]T. Twin of
|
||||
// cstage arrlit_init_fits' slice arm. Local-only (c.cur != c.top): the
|
||||
// borrow runs at runtime; module-level slice-from-arrlit stays #32.
|
||||
if (c.cur != c.top && n.lhs.kind == syntax.nkind.N_TSLICE
|
||||
&& n.rhs.kind == syntax.nkind.N_ARRLIT) {
|
||||
// [count]T), then drive isassignable off [count]T. Twin of cstage
|
||||
// arrlit_init_fits' slice arm (cmd/wcc/check.c:519-520). #28/#32: this
|
||||
// admission runs at BOTH scopes. The matching DATA-vs-borrow split is
|
||||
// the desugar at the foot of this fn (gated c.cur != c.top): a LOCAL
|
||||
// `let []u8 = [...]` lowers to a runtime arr[0:len] borrow, while a
|
||||
// MODULE-level `const/let []u8 = [...]` keeps its raw N_ARRLIT for cgen
|
||||
// to materialize as DATA (#18). cstage admits both — module-level via
|
||||
// arrlit_init_fits in check_file pass-2 (check.c:3406-3409), which never
|
||||
// desugars — so gating the admission local-only made wwstage REJECT
|
||||
// valid Hare (`const dotdot: []u8 = ['.', '.'];` ref/hare/path/stack.ha:30).
|
||||
// #28: a TUPLE-element slice global ([](str,*fn) tables) is EXCLUDED at
|
||||
// module scope — the synthesis delegates per-element validation to
|
||||
// checkarrlitfits, whose element check is isassignable, which has NO
|
||||
// strict tuple arm (#38). cstage's arrlit_init_fits uses type_assignable
|
||||
// (strict on tuples), so routing a tuple-element slice through the
|
||||
// synthesis would over-accept a sig-mismatched `&fn` element that cstage
|
||||
// rejects (#124 wrong_sig_table). Tuple-element slices instead stay on
|
||||
// the natural whole-element typeeqast path below (isassignable's #258
|
||||
// array→slice arm), which IS strict and reaches cstage's same decision.
|
||||
let elemtup: bool = false;
|
||||
if (c.cur == c.top && n.lhs.lhs != nil) {
|
||||
let etn: *syntax.node = resolvealias(c, unwrapbang(n.lhs.lhs));
|
||||
if (etn != nil && etn.kind == syntax.nkind.N_TTUPLE) {
|
||||
elemtup = true;
|
||||
};
|
||||
};
|
||||
if (n.lhs.kind == syntax.nkind.N_TSLICE
|
||||
&& n.rhs.kind == syntax.nkind.N_ARRLIT && !elemtup) {
|
||||
let cnt: u64 = 0u64;
|
||||
let e0: *syntax.node = n.rhs.list;
|
||||
for (e0 != nil) {
|
||||
@@ -6007,7 +6030,13 @@ fn checkletassign(c: *checker, n: *syntax.node) void = {
|
||||
// can size the backing NODE-wise via elemsizeofc(base.lhs). wwstage
|
||||
// narrow-primitive tinfos are unsized (i32/u8 .size==0, #8), so the
|
||||
// element width must come from the type NODE, not the tinfo.
|
||||
n.rhs.lhs = arr;
|
||||
// #28: LOCAL ONLY. The local desugar replaces n.rhs with the N_SLICE
|
||||
// borrow, so this stash is consumed and then unreachable. A MODULE-
|
||||
// level decl keeps its raw N_ARRLIT (DATA emit), and its emitslicedata
|
||||
// sizes off the DECLARED slice tnode (d.lhs), never the stash — so the
|
||||
// stash would only leave the synthesized, untyped count node (cn) on
|
||||
// the live tree for the pass-3 asserttyped walker to trip on.
|
||||
if (c.cur != c.top) { n.rhs.lhs = arr; };
|
||||
src = arr;
|
||||
};
|
||||
// #29: an un-suffixed rune literal narrowing into an integer let target
|
||||
|
||||
Reference in New Issue
Block a user