From 6f2ed0cc57d984106444f185ab35113ee989558a Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 12 Jun 2026 11:24:58 +0900 Subject: [PATCH] wcc/ww: reject non-tuple multi-assign rhs (resolvewalk N_MASSIGN) ww accepted a non-tuple rhs in a destructuring assignment that cstage rejects (check.c:2562); the destructure then read garbage words. --- selfhost/cmd/w6c/main.combined.ww | 16 ++++++++++++++-- selfhost/cmd/wcc/check.ww | 16 ++++++++++++++-- selfhost/cmd/wwdump/main.combined.ww | 16 ++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 3a188784..0b6f7b44 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -11096,9 +11096,21 @@ fn resolvewalk(c: *checker, n: *node) void = { // #242: consume the rhs tuple type for ANY rhs (see N_MLET). if (n.rhs != nil) { let rty: *node = exprtype(c, n.rhs, nil); - if (rty != nil) { if (rty.kind == nkind.N_TTUPLE) { + if (rty != nil && rty.kind == nkind.N_TTUPLE) { pt = rty.list; - }; }; + } else { + // #38/F2 (review item 39): the multi-assign rhs must be a + // tuple. cstage check.c:2562-2568 errors "multi-assign rhs + // is not a tuple (got %s)" when cexpr(rhs)->kind != TY_TUPLE + // — and, like ww's exprtype (N_CALL returns the decl's bare + // return tnode, :3319), it does NOT chase the NAMED wrapper, + // so a tuple-ALIAS return (`fn f() pair`) is rejected too. + // Without this ww distributed nil element widths and + // cgmassign silently dropped the str len/cap stores. ww's + // piecewise cerr can't splice the type spelling, so the + // "(got %s)" tail is omitted. + deffolderr(c, n, "multi-assign rhs is not a tuple"); + }; }; let l: *node = n.list; for (l != nil) { resolvewalk(c, l); l = l.next; }; diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 56518a88..643ded62 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -676,9 +676,21 @@ fn resolvewalk(c: *checker, n: *node) void = { // #242: consume the rhs tuple type for ANY rhs (see N_MLET). if (n.rhs != nil) { let rty: *node = exprtype(c, n.rhs, nil); - if (rty != nil) { if (rty.kind == nkind.N_TTUPLE) { + if (rty != nil && rty.kind == nkind.N_TTUPLE) { pt = rty.list; - }; }; + } else { + // #38/F2 (review item 39): the multi-assign rhs must be a + // tuple. cstage check.c:2562-2568 errors "multi-assign rhs + // is not a tuple (got %s)" when cexpr(rhs)->kind != TY_TUPLE + // — and, like ww's exprtype (N_CALL returns the decl's bare + // return tnode, :3319), it does NOT chase the NAMED wrapper, + // so a tuple-ALIAS return (`fn f() pair`) is rejected too. + // Without this ww distributed nil element widths and + // cgmassign silently dropped the str len/cap stores. ww's + // piecewise cerr can't splice the type spelling, so the + // "(got %s)" tail is omitted. + deffolderr(c, n, "multi-assign rhs is not a tuple"); + }; }; let l: *node = n.list; for (l != nil) { resolvewalk(c, l); l = l.next; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 725f7f61..5a96022e 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -11096,9 +11096,21 @@ fn resolvewalk(c: *checker, n: *node) void = { // #242: consume the rhs tuple type for ANY rhs (see N_MLET). if (n.rhs != nil) { let rty: *node = exprtype(c, n.rhs, nil); - if (rty != nil) { if (rty.kind == nkind.N_TTUPLE) { + if (rty != nil && rty.kind == nkind.N_TTUPLE) { pt = rty.list; - }; }; + } else { + // #38/F2 (review item 39): the multi-assign rhs must be a + // tuple. cstage check.c:2562-2568 errors "multi-assign rhs + // is not a tuple (got %s)" when cexpr(rhs)->kind != TY_TUPLE + // — and, like ww's exprtype (N_CALL returns the decl's bare + // return tnode, :3319), it does NOT chase the NAMED wrapper, + // so a tuple-ALIAS return (`fn f() pair`) is rejected too. + // Without this ww distributed nil element widths and + // cgmassign silently dropped the str len/cap stores. ww's + // piecewise cerr can't splice the type spelling, so the + // "(got %s)" tail is omitted. + deffolderr(c, n, "multi-assign rhs is not a tuple"); + }; }; let l: *node = n.list; for (l != nil) { resolvewalk(c, l); l = l.next; };