check: lower an array-variable borrow into a union slice success variant (#17)

This commit is contained in:
2026-06-28 10:43:34 +09:00
parent fa1b6b77d4
commit 5fb18876b9
3 changed files with 147 additions and 0 deletions

View File

@@ -5639,6 +5639,25 @@ fn desugararrayslice(c: *checker, dsttn: *syntax.node, srctn: *syntax.node, val:
let su: *syntax.node = resolvealias(c, unwrapbang(srctn));
if (du == nil) { return val; };
if (su == nil) { return val; };
// #17: the borrow target may be the SLICE success variant of a tagged
// union (`return/assign/let/f(arr)` into `([]T|e)`). Chase du to that
// variant so an array VARIABLE lowers to a full slice exactly as a bare
// []T dst does — the existing slice cgen then builds the full
// {ptr,len,cap} header and the union widen's slice arm wraps it, closing
// the silent len/cap drop. Mirrors #13's rejectarrlitborrow N_TTAGGED
// chase (an array LITERAL has no outliving backing and is rejected there
// first; a variable has storage, so this borrow is legal).
if (du.kind == syntax.nkind.N_TTAGGED && su.kind == syntax.nkind.N_TARRAY) {
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 && typeeqast(c, vu.lhs, su.lhs)) {
du = vu;
break;
};
v = v.next;
};
};
if (du.kind != syntax.nkind.N_TSLICE) { return val; };
if (su.kind != syntax.nkind.N_TARRAY) { return val; };
if (!typeeqast(c, du.lhs, su.lhs)) { return val; };