Align bare-int array-init assignability to Hare's literal-fits rule (ref/harec/src/types.c promote_flexible): accept untyped-int array elements that FIT the element type, reject out-of-range loud. cstage (rejected all bare-int arrays, over-strict) and wwstage (accepted + silently truncated out-of-range, over-loose) converge to the same accept-if-fits rule. Per-element: foldable int literal range-checked against element type [min,max] via def_cast_fits (rule-13 type-table widths); non-foldable element falls back to type_assignable. cstage: new arrlit_init_fits, N_LET decl-check fallback after whole- array type_assignable fails. wwstage: checkletassign array branch + route top-level lets through checkletassign (were unchecked — only function-body lets ran assignability; closes #146 wwstage str->u8 over-accept). Scalar-init range-check (let X:u8=300 truncates, both stages, pre-existing) deferred to #148 — language-wide, needs bootstrap audit + explicit-cast conversion. def-array accept-if-fits deferred to #151 (def constfold machinery, different risk). Both bootstrap-NEUTRAL. Test 920 (14 rows — accept: in-range u8/u32/u64/i32 + u8/i8 boundary + typed regression + non-foldable-body; reject: over-range + over-256 + i8-over + neg-for-unsigned + str->u8 + non-foldable-wider). Non- foldable else-branch cs==ww verified (matching-type accept + byte-id; wider-runtime-int reject both stages). Make test: 183/183 incl 990-997 byte-id + combined_ww_fresh.
This commit is contained in:
@@ -10673,6 +10673,66 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #130: array-init accept-if-fits. When lhs is [N]T and rhs is an
|
||||
// array literal, per-element check: foldable int literal →
|
||||
// defcastfits range-check (reject out-of-range loud, rule-7/Drew —
|
||||
// Hare range-checks at literal-value level); non-foldable →
|
||||
// isassignable to the element type. This BOTH accepts in-range
|
||||
// bare-int (the #130 headline, matching cstage) AND closes the
|
||||
// wwstage over-accept where str→u8 / out-of-range silently passed
|
||||
// (#146 merged). Mirrors cstage check.c arrlit_init_fits. Scoped
|
||||
// to the array path; scalar-init range-check is a separate
|
||||
// language-wide gap (#148).
|
||||
if (n.lhs.kind == nkind.N_TARRAY) {
|
||||
if (n.rhs.kind == nkind.N_ARRLIT) {
|
||||
let elemtn: *node = n.lhs.lhs;
|
||||
let at: *tinfo = tinfofornode(c, n.lhs);
|
||||
let et: *tinfo = nil;
|
||||
if (at != nil) { et = at.sub; };
|
||||
for (et != nil && et.kind == tykind.TY_NAMED) { et = et.under; };
|
||||
let e: *node = n.rhs.list;
|
||||
for (e != nil) {
|
||||
let skip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) { skip = true; };
|
||||
};
|
||||
if (!skip) {
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||
let v: u64 = 0u64;
|
||||
let folded: bool = false;
|
||||
if (et != nil) {
|
||||
if (typeisint(et)) {
|
||||
if (ev != nil) {
|
||||
folded = foldintliteral(ev, &v);
|
||||
};
|
||||
};
|
||||
};
|
||||
if (folded) {
|
||||
if (!defcastfits(et, v)) {
|
||||
let m: str = "let: array element out of range\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
c.errs += 1;
|
||||
return;
|
||||
};
|
||||
} else {
|
||||
let est: *node = exprtype(c, ev, elemtn);
|
||||
let conf2: bool = false;
|
||||
if (est != nil) {
|
||||
if (!isassignable(c, elemtn, est, &conf2)) {
|
||||
if (conf2) {
|
||||
errnotassign(c, elemtn, est, "let");
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
e = e.next;
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
let conf: bool = false;
|
||||
let ok: bool = isassignable(c, n.lhs, src, &conf);
|
||||
if (!conf) { return; };
|
||||
@@ -11052,6 +11112,13 @@ export fn checkfile(c: *checker, file: *node) void = {
|
||||
} else { if (k == nkind.N_LET) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||
if (d.rhs != nil) { resolvewalk(c, d.rhs); };
|
||||
// #130: top-level let assignability — the subtree
|
||||
// resolvewalk above stamps types but never runs the
|
||||
// init-assignability check (function-body lets get it
|
||||
// via resolvewalk's post-order L247; top-level lets
|
||||
// were missed). Needed for the array accept-if-fits
|
||||
// range-check to fire on module-level `let A:[N]u8=[..]`.
|
||||
checkletassign(c, d);
|
||||
};};};};
|
||||
d = d.next;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user