diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 1cc8dd81..e9b5e468 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -14477,8 +14477,22 @@ fn checkletassign(c: *checker, n: *node) void = { if (!ok) { if (assignableaddrfn(c, n.lhs, n.rhs)) { ok = true; }; }; if (!conf) { return; }; if (!ok) { errnotassign(c, n.lhs, src, "let"); }; - // #258: `let s: []T = arr` borrows the array as a full slice. - n.rhs = desugararrayslice(c, n.lhs, src, n.rhs); + // #258: `let s: []T = arr` borrows the array as a full slice. The + // desugar lowers to a runtime `arr[0:len]` N_SLICE, so it only + // applies to LOCAL lets (a fn body executes the borrow). A MODULE- + // level let is static data with no runtime to run the borrow — its + // rhs must stay the raw N_ARRLIT so cgen can materialize it as DATA + // (#18). cstage splits this by checker: clet (the desugar site, + // cmd/wcc/check.c:1993) runs only from cstmt (local), while module- + // level lets are checked in check_file pass-2 (check.c:2549) which + // never desugars. wwstage runs ONE checkletassign for both (pass-2 + // @checkfile + resolvewalk post-order), so mirror cstage's split + // here: skip at module scope (c.cur == c.top, the same module-scope + // test as L184). Keeps the #130 module-level assignability check + // above intact. + if (c.cur != c.top) { + n.rhs = desugararrayslice(c, n.lhs, src, n.rhs); + }; }; fn checkretassign(c: *checker, n: *node) void = { diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 93393efe..04241ea5 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -4110,8 +4110,22 @@ fn checkletassign(c: *checker, n: *node) void = { if (!ok) { if (assignableaddrfn(c, n.lhs, n.rhs)) { ok = true; }; }; if (!conf) { return; }; if (!ok) { errnotassign(c, n.lhs, src, "let"); }; - // #258: `let s: []T = arr` borrows the array as a full slice. - n.rhs = desugararrayslice(c, n.lhs, src, n.rhs); + // #258: `let s: []T = arr` borrows the array as a full slice. The + // desugar lowers to a runtime `arr[0:len]` N_SLICE, so it only + // applies to LOCAL lets (a fn body executes the borrow). A MODULE- + // level let is static data with no runtime to run the borrow — its + // rhs must stay the raw N_ARRLIT so cgen can materialize it as DATA + // (#18). cstage splits this by checker: clet (the desugar site, + // cmd/wcc/check.c:1993) runs only from cstmt (local), while module- + // level lets are checked in check_file pass-2 (check.c:2549) which + // never desugars. wwstage runs ONE checkletassign for both (pass-2 + // @checkfile + resolvewalk post-order), so mirror cstage's split + // here: skip at module scope (c.cur == c.top, the same module-scope + // test as L184). Keeps the #130 module-level assignability check + // above intact. + if (c.cur != c.top) { + n.rhs = desugararrayslice(c, n.lhs, src, n.rhs); + }; }; fn checkretassign(c: *checker, n: *node) void = { diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index a861f708..8a02399c 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -14477,8 +14477,22 @@ fn checkletassign(c: *checker, n: *node) void = { if (!ok) { if (assignableaddrfn(c, n.lhs, n.rhs)) { ok = true; }; }; if (!conf) { return; }; if (!ok) { errnotassign(c, n.lhs, src, "let"); }; - // #258: `let s: []T = arr` borrows the array as a full slice. - n.rhs = desugararrayslice(c, n.lhs, src, n.rhs); + // #258: `let s: []T = arr` borrows the array as a full slice. The + // desugar lowers to a runtime `arr[0:len]` N_SLICE, so it only + // applies to LOCAL lets (a fn body executes the borrow). A MODULE- + // level let is static data with no runtime to run the borrow — its + // rhs must stay the raw N_ARRLIT so cgen can materialize it as DATA + // (#18). cstage splits this by checker: clet (the desugar site, + // cmd/wcc/check.c:1993) runs only from cstmt (local), while module- + // level lets are checked in check_file pass-2 (check.c:2549) which + // never desugars. wwstage runs ONE checkletassign for both (pass-2 + // @checkfile + resolvewalk post-order), so mirror cstage's split + // here: skip at module scope (c.cur == c.top, the same module-scope + // test as L184). Keeps the #130 module-level assignability check + // above intact. + if (c.cur != c.top) { + n.rhs = desugararrayslice(c, n.lhs, src, n.rhs); + }; }; fn checkretassign(c: *checker, n: *node) void = {