wcc/ww: flexible rune-const promotion at scalar seams (coercerunelit)
wwstage stamped N_RUNELIT as concrete rune (cstage: untyped_rune, check.c:1296), so an uncast rune literal into a fitting integer slot over-rejected where harec accepts (promote_flexible). Add coercerunelit (mirror of coercefloatlit) at the scalar seams — let-init, return, call-arg, index-store; coarse accept, no range check (mirror cstage type.c:379); array-literal elements keep the range gate (arrlit_init_fits, types.c:923). Teeth: the fnmatch.ww '\\': u8 workaround cast and getopttest's 'X': u8 index-store casts are removed and compile green. Checker-only (no e.type_ restamp): byte-id held.
This commit is contained in:
@@ -12756,6 +12756,48 @@ fn coercefloatlit(c: *checker, e: *node, target: *node) void = {
|
||||
};
|
||||
};
|
||||
|
||||
// coercerunelit — #29: an un-suffixed rune literal narrowing into an
|
||||
// integer slot. Same intent as coercefloatlit (:2324) but CHECKER-only:
|
||||
// wwstage stamps N_RUNELIT concrete `rune` (:2652), so isassignable's
|
||||
// untyped arms never fire and the operand falls to the "two known
|
||||
// primitives, different names → confident reject" arm (:4139) — the #29
|
||||
// over-reject. cstage stamps N_RUNELIT untyped_rune (cmd/wcc/check.c:1296)
|
||||
// which type_assignable admits into ANY integer UNCONDITIONALLY
|
||||
// (cmd/wcc/type.c:379 — coarse, NO range check; harec's range-precise
|
||||
// promote_flexible at types.c:928 is the reference cstage already
|
||||
// flattened, so wwstage mirrors cstage's coarse rule, not harec's gate).
|
||||
// Return the integer target tnode so the caller overrides its `src`/
|
||||
// `atype` and isassignable sees su==target → accept. Does NOT touch
|
||||
// e.type_: cgen narrows a rune immediate by the DESTINATION width (proven
|
||||
// byte-id at let/call-arg/index-store; #251 array-elem twin) and for a
|
||||
// tagged-union target the variant boxing falls to taggedvariantindext's
|
||||
// scalar-shape fallback (cgenutil.ww:3054) which picks the first scalar
|
||||
// variant — the same u8 variant cstage's untyped_rune boxes into — so the
|
||||
// unchanged node stamp keeps cgen provably identical to the pre-fix
|
||||
// bare-literal lowering. Array-LITERAL elements are NOT routed here: they
|
||||
// keep harec's per-element range gate via checkarrlitfits's foldint /
|
||||
// defcastfits path (:4634). For a tagged-union target (fnmatch pat_next's
|
||||
// (u8 | star | ...)) return the first integer variant.
|
||||
fn coercerunelit(c: *checker, e: *node, target: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
if (e.kind != nkind.N_RUNELIT) { return nil; };
|
||||
if (target == nil) { return nil; };
|
||||
let tu: *node = resolvealias(c, unwrapbang(target));
|
||||
if (tu == nil) { return nil; };
|
||||
if (isinttypeast(tu)) { return tu; };
|
||||
if (tu.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = tu.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (isinttypeast(vu)) { return vu; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
// binoptype — derive the result tnode of an N_BIN operator expression.
|
||||
// Mirrors cstage cmd/wcc/check.c:598-640 `cbinop`. Operates on tnodes
|
||||
// returned by exprtype; ptr arithmetic / bitwise / shifts / comparisons /
|
||||
@@ -15215,6 +15257,14 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
||||
if (param.kind == nkind.N_PARAM) {
|
||||
if (param.op != tkind.TK_ELLIPSIS) {
|
||||
let atype: *node = exprtype(c, a, nil);
|
||||
// #29: a rune literal narrowing into an integer param
|
||||
// (`take('b')` where take(b: u8)). Override atype to the
|
||||
// integer target so c3's general isassignable accepts,
|
||||
// mirroring cstage's coarse untyped_rune rule. See
|
||||
// coercerunelit. cgen is byte-id-neutral (narrows by the
|
||||
// param/destination width).
|
||||
let runet: *node = coercerunelit(c, a, param.lhs);
|
||||
if (runet != nil) { atype = runet; };
|
||||
// #258: an array arg into a []T param with a
|
||||
// MISMATCHED element is not a borrow — loud reject,
|
||||
// mirror cstage's call-arg type_assignable failure.
|
||||
@@ -15267,6 +15317,13 @@ fn checkassign(c: *checker, n: *node) void = {
|
||||
if (n.rhs == nil) { return; };
|
||||
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
|
||||
// target (`buf[i] = 'F'`). Override rtn to the integer target so a
|
||||
// general assign typecheck accepts, mirroring cstage's coarse
|
||||
// untyped_rune rule. See coercerunelit. cgen narrows by the destination
|
||||
// width (byte-id-neutral). Removes the getopt `'X': u8` index casts.
|
||||
let runet: *node = coercerunelit(c, n.rhs, ltn);
|
||||
if (runet != nil) { rtn = runet; };
|
||||
// #31/#33: bare array-literal rhs has no backing — loud-reject
|
||||
// (supported only at a `let`).
|
||||
if (!rejectarrlitborrow(c, ltn, n.rhs)) {
|
||||
@@ -15508,6 +15565,11 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
n.rhs.lhs = arr;
|
||||
src = arr;
|
||||
};
|
||||
// #29: an un-suffixed rune literal narrowing into an integer let target
|
||||
// (`let b: u8 = 'a'`). Override src to the integer target so isassignable
|
||||
// accepts, mirroring cstage's coarse untyped_rune rule. See coercerunelit.
|
||||
let runet: *node = coercerunelit(c, n.rhs, n.lhs);
|
||||
if (runet != nil) { src = runet; };
|
||||
let conf: bool = false;
|
||||
let ok: bool = isassignable(c, n.lhs, src, &conf);
|
||||
// #206: direct `&fn` → `*alias` / `(*alias | void)` slot.
|
||||
@@ -15573,6 +15635,12 @@ fn checkretassign(c: *checker, n: *node) void = {
|
||||
};
|
||||
let src: *node = exprtype(c, n.lhs, nil);
|
||||
if (src == nil) { return; };
|
||||
// #29: a rune literal returned into an integer (or integer-variant)
|
||||
// fnret (`return '\\';` into u8 or (u8 | star | ...)). Override src so
|
||||
// isassignable accepts; cgen boxes via the shape fallback. See
|
||||
// coercerunelit. Removes the fnmatch.ww:126 `'\\': u8` workaround cast.
|
||||
let runet: *node = coercerunelit(c, n.lhs, c.fnret);
|
||||
if (runet != nil) { src = runet; };
|
||||
let conf: bool = false;
|
||||
let ok: bool = isassignable(c, c.fnret, src, &conf);
|
||||
// #206: direct `&fn` returned into a `*alias` / `(*alias | void)`.
|
||||
|
||||
Reference in New Issue
Block a user