check: reject an array-literal borrow into a union slice success variant (#13)

A stack array literal returned into a tagged-union slice success variant (fn mk() ([]i32|e) = { return [10,20,30]; }) slipped past reject_arrlit_borrow — it bailed when the dst was not TY_SLICE, but a union dst is TY_TAGGED — so cgen built an all-zeros slice header: a silent both-stage miscompile (and the .ptr would dangle anyway, no outliving backing). Extend the reject to chase a TY_TAGGED dst to its slice success variant, then apply the existing reject; this is the #25/#31 treatment seen through the union, and matches Hare (rule-9). Reached by all acceptance sites (return/assign/call-arg) so the class closes by construction. Both stages converge on an identical accept/reject decision (an array literal assignable to a union is assignable to a slice or array variant; neither stage can accept it). Full support — promoting the literal to an outliving backing — is the separate #33 arc. Compile-error fixture + a positive over-reach guard (a real slice into the union still compiles). No asm emitted by a reject, so byte-id is unchanged (no floor ratchet).
This commit is contained in:
2026-06-28 02:44:23 +09:00
parent 01649598f4
commit 6b36b050d7
4 changed files with 61 additions and 0 deletions

View File

@@ -5607,6 +5607,23 @@ fn rejectarrlitborrow(c: *checker, dsttn: *syntax.node, val: *syntax.node) bool
if (val.kind != syntax.nkind.N_ARRLIT) { return false; };
let du: *syntax.node = resolvealias(c, unwrapbang(dsttn));
if (du == nil) { return false; };
// #13: the borrow target may be a SLICE success variant of a tagged-
// union return — same no-outliving-backing dangle, but it slips the
// N_TSLICE gate (the dst node chases to N_TTAGGED). Chase to a slice
// variant so the reject sees through the union. An N_ARRLIT can only
// target a slice variant; an array-typed variant is the #5/#60 reject
// upstream; full non-let support is #33. Twin of cstage #13 arm.
if (du.kind == syntax.nkind.N_TTAGGED) {
let v: *syntax.node = du.list;
for (v != nil) {
let vu: *syntax.node = resolvealias(c, unwrapbang(v));
if (vu != nil && vu.kind == syntax.nkind.N_TSLICE) {
du = vu;
break;
};
v = v.next;
};
};
if (du.kind != syntax.nkind.N_TSLICE) { return false; };
let m: str = "array literal cannot borrow as a slice here; bind it to a `let` first\n";
cerr(m);