wcc/ww: reject reassignment of a const binding (catB-22)
The sym carried an is_const flag (lib/ww/sym.ww) but wwstage never set it at the let-install nor consumed it at assignment, so mutating a `const` slipped through silently. Mirror cstage's two sites: set is_const when n.op == TK_CONST at the local let-install (cmd/wcc/ check.c:2408) and reject an N_ASSIGN whose lhs ident resolves to an is_const sym (cmd/wcc/check.c:1889-1896). cstage already rejected; this aligns wwstage's w6c_ww UP. A bare `_` discard lvalue (empty str) is skipped. Regen w6c/wwdump combined.ww (checker embeds in both). Valid-program codegen unchanged → cs==ww byte-id gate stays green.
This commit is contained in:
@@ -773,7 +773,14 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
let nm: str = n.str;
|
||||
if (nm.len > 0) {
|
||||
checkmoduleshadow(c, nm, "let");
|
||||
scopedefine(c.cur, nm, skind.SK_VAR, nil, n);
|
||||
let s: *sym = scopedefine(c.cur, nm, skind.SK_VAR, nil, n);
|
||||
// catB-22: flag a `const` binding so checkassign can
|
||||
// reject a later reassignment. The parser stamps
|
||||
// n.op = TK_CONST (parse/stmt.ww). Mirror cstage
|
||||
// cmd/wcc/check.c:2408.
|
||||
if (s != nil) {
|
||||
if (n.op == tkind.TK_CONST) { s.is_const = 1i32; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5473,6 +5480,21 @@ fn checkassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) { return; };
|
||||
if (n.rhs == nil) { return; };
|
||||
// catB-22: reject reassigning a `const`-flagged binding (the
|
||||
// is_const bit set at the let-install above). A bare `_` discard
|
||||
// lvalue carries an empty str and is skipped. Mirror cstage
|
||||
// cmd/wcc/check.c:1889-1896.
|
||||
if (n.lhs.kind == nkind.N_IDENT) {
|
||||
if (n.lhs.str.len > 0) {
|
||||
let s: *sym = scopelookupprefer(c.cur, c.curmod, n.lhs.str);
|
||||
if (s != nil) {
|
||||
if (s.is_const != 0i32) {
|
||||
cerr("error: cannot assign to const binding\n");
|
||||
c.errs += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
let ltn: *node = exprtype(c, n.lhs, nil);
|
||||
let rtn: *node = exprtype(c, n.rhs, nil);
|
||||
// #29: a rune literal narrowing into an integer assign/index-store
|
||||
|
||||
Reference in New Issue
Block a user