wcc/check: #25 reject overlong array-lit in a tuple return (wwstage)

This commit is contained in:
2026-06-09 15:01:34 +09:00
parent 89f3e58458
commit f767819b41
4 changed files with 60 additions and 0 deletions

View File

@@ -15123,6 +15123,19 @@ fn checkretassign(c: *checker, n: *node) void = {
if (n.lhs.kind == nkind.N_ARRLIT) {
checkarrlitfits(c, c.fnret, n.lhs);
};
// #25: array-typed element of a TUPLE RETURN with an overlong array
// literal — `fn f() ([2]int,i32) = { return ([1,2,3],5); }`. #20
// wired the tuple over-fill walk at the LET position only; the
// return path runs through checkretassign which never routed tuple
// elements through checkarrlitfits. Reuse the #26 helper. Fire
// BEFORE the isassignable/conf guards (a tuple return drives
// conf=false → short-circuit), same reason as the #12 array arm
// above. Alias/!-aware on the fnret tuple type.
let rrt: *node = resolvealias(c, unwrapbang(c.fnret));
if (rrt != nil && rrt.kind == nkind.N_TTUPLE
&& n.lhs.kind == nkind.N_TUPLE) {
checktuplearrfits(c, rrt, n.lhs);
};
let src: *node = exprtype(c, n.lhs, nil);
if (src == nil) { return; };
let conf: bool = false;

View File

@@ -4842,6 +4842,19 @@ fn checkretassign(c: *checker, n: *node) void = {
if (n.lhs.kind == nkind.N_ARRLIT) {
checkarrlitfits(c, c.fnret, n.lhs);
};
// #25: array-typed element of a TUPLE RETURN with an overlong array
// literal — `fn f() ([2]int,i32) = { return ([1,2,3],5); }`. #20
// wired the tuple over-fill walk at the LET position only; the
// return path runs through checkretassign which never routed tuple
// elements through checkarrlitfits. Reuse the #26 helper. Fire
// BEFORE the isassignable/conf guards (a tuple return drives
// conf=false → short-circuit), same reason as the #12 array arm
// above. Alias/!-aware on the fnret tuple type.
let rrt: *node = resolvealias(c, unwrapbang(c.fnret));
if (rrt != nil && rrt.kind == nkind.N_TTUPLE
&& n.lhs.kind == nkind.N_TUPLE) {
checktuplearrfits(c, rrt, n.lhs);
};
let src: *node = exprtype(c, n.lhs, nil);
if (src == nil) { return; };
let conf: bool = false;

View File

@@ -15123,6 +15123,19 @@ fn checkretassign(c: *checker, n: *node) void = {
if (n.lhs.kind == nkind.N_ARRLIT) {
checkarrlitfits(c, c.fnret, n.lhs);
};
// #25: array-typed element of a TUPLE RETURN with an overlong array
// literal — `fn f() ([2]int,i32) = { return ([1,2,3],5); }`. #20
// wired the tuple over-fill walk at the LET position only; the
// return path runs through checkretassign which never routed tuple
// elements through checkarrlitfits. Reuse the #26 helper. Fire
// BEFORE the isassignable/conf guards (a tuple return drives
// conf=false → short-circuit), same reason as the #12 array arm
// above. Alias/!-aware on the fnret tuple type.
let rrt: *node = resolvealias(c, unwrapbang(c.fnret));
if (rrt != nil && rrt.kind == nkind.N_TTUPLE
&& n.lhs.kind == nkind.N_TUPLE) {
checktuplearrfits(c, rrt, n.lhs);
};
let src: *node = exprtype(c, n.lhs, nil);
if (src == nil) { return; };
let conf: bool = false;

View File

@@ -25,6 +25,8 @@
* tuple_arr_over | let t:([2]int,i32)=([1,2,3],5) | b. FAIL
* tuple_nested_arr | let t:([2][3]int,i32)=([[..],[..],[..]],5) | b. FAIL
* tuple_in_tuple | let t:([2]int,([2]int,i32))=([..],([1,2,3],.))| #26 FAIL
* tuple_return_over | fn()([2]int,i32){return([1,2,3],5)} | #25 FAIL
* tuple_return_nested| fn()([2]int,([2]int,i32)){return(..,([..3],.))| #25 FAIL
*
* pos row | shape | want
* -------------------+----------------------------------------------+------
@@ -116,6 +118,25 @@ static const char *neg[] = {
"\tlet t: ([2]int, ([2]int, i32)) = ([1, 2], ([3, 4, 5], 6));\n"
"\treturn t.0[0]: i32;\n"
"};\n",
/* tuple_return_over (#25) — overlong [2]int in a tuple RETURN. */
"package main;\n"
"fn f() ([2]int, i32) = {\n"
"\treturn ([1, 2, 3], 5);\n"
"};\n"
"export fn main() i32 = {\n"
"\tlet t = f();\n"
"\treturn t.1;\n"
"};\n",
/* tuple_return_nested (#25 path × #26 recursion) — nested tuple in a
* RETURN, inner [2]int over-filled. */
"package main;\n"
"fn f() ([2]int, ([2]int, i32)) = {\n"
"\treturn ([1, 2], ([3, 4, 5], 6));\n"
"};\n"
"export fn main() i32 = {\n"
"\tlet t = f();\n"
"\treturn t.0[0]: i32;\n"
"};\n",
};
static int