w6c+wwstage: narrow int/rune array-literal elements to the declared type (#251)
`let a:[4]u8=[65,66,67,68]`, `def D:[4]u8=['A',..]`, and `enc{m=[65,..]}`
rejected with "init [4]i32 not assignable to declared [4]u8": an array
literal's element type came from the elements via type_default (int-lit
-> i32, rune-lit -> rune) with no declared-element-type propagation. The
scalar path already narrows (`let c:u8='A'`); only array aggregation at
the let/def/struct-field sites #130 (test 920) left unwired did not.
Fix = the int/rune analogue of coerce_floatlit, realised as the EXISTING
#130 accept-if-fits range-check — NOT a node-type restamp. cgen drives
the array element WIDTH from the declared type at every site (cgen.c
local-let lu->sub, emit_array_data d->type), so a restamp would be dead
code (the array literal keeps its [N]i32/[N]rune node type; the cs==ww
byte-id gate confirms the bytes emit u8-wide regardless). Per element:
foldable int/rune literal -> defcastfits range-check vs declared T
(in-range accept, out-of-range REJECT loud, rule-7); non-foldable ->
type_assignable / isassignable.
cstage (check.c): wire arrlit_init_fits into clet (local let),
struct-field-init, and def-init — the three sites the #130 module-let
path already covered.
wwstage (check.ww): factor checkletassign's inline #130 block into
checkarrlitfits and call it from the let path, the def path, and a
TARGETED array-field walk in the N_STRUCTLIT arm. This also closes a
pre-existing rule-7 wwstage over-accept: the def path ran NO init
assignability check and the N_STRUCTLIT head-stamp parks field
assignability (#23), so out-of-range / str array elements silently
over-accepted (a truncating miscompile) at those two sites. The
struct-field walk is the array-field accept-if-fits ONLY — it reuses the
stable N_TSTRUCT field-list walk (astoffset precedent), isolated from
the broader parked #23 field-assignability walk.
Regenerated w6c + wwdump combined.ww (embed check.ww). New test 951
covers let/def/struct-field x int/rune accept (run + cs==ww byte-id) and
out-of-range/str reject (both stages). test-unit 237 + smoke green.
This commit is contained in:
@@ -1542,6 +1542,7 @@ cexpr(Checker *c, Node *n)
|
||||
f->str, type_name(c->a, t));
|
||||
else if (vt != ty_err &&
|
||||
!type_assignable(match->type, vt) &&
|
||||
!arrlit_init_fits(c, match->type, f->lhs) &&
|
||||
!assignable_addrfn(c, match->type, f->lhs))
|
||||
err(c, f->pos, "field %s: %s not assignable to %s",
|
||||
f->str, type_name(c->a, vt),
|
||||
@@ -1897,6 +1898,7 @@ clet(Checker *c, Node *n)
|
||||
}
|
||||
if (declared && initt && initt != ty_err && !has_arr_repeat &&
|
||||
!type_assignable(declared, initt) &&
|
||||
!arrlit_init_fits(c, declared, n->rhs) &&
|
||||
!assignable_addrfn(c, declared, n->rhs))
|
||||
err(c, n->pos, "init %s not assignable to declared %s",
|
||||
type_name(c->a, initt), type_name(c->a, declared));
|
||||
@@ -2422,7 +2424,8 @@ check_file(Checker *c, Node *file)
|
||||
&& def_cast_fits(d->type, dv))
|
||||
art = ty_untyped_int;
|
||||
if (d->type && rt != ty_err && d->type != ty_err
|
||||
&& !type_assignable(d->type, art))
|
||||
&& !type_assignable(d->type, art)
|
||||
&& !arrlit_init_fits(c, d->type, d->rhs))
|
||||
err(c, d->pos, "def %s init %s not assignable to %s",
|
||||
d->str, type_name(c->a, rt),
|
||||
type_name(c->a, d->type));
|
||||
|
||||
Reference in New Issue
Block a user