selfhost/cmd/wcc: extend enum fold to constexpr set (A.6.2.1a)
check.ww's N_DOT enum-fold (L1724-1810) walks the enum body to resolve each `EnumT.MEMBER` access; the pre-#22 walker only accepted N_INTLIT for a member's lhs and bailed on every richer shape via `return nil`. Wwstage compensated at codegen time through cgen.ww's enumevalmember (cgen.ww:158-227), so program semantics held; the gap was visible only in check.ww's e.type_ stamp coverage, which A.6.2.1e's post-checker assertion will land on. Lift the literal-only branch into an `enumvalfold(body, until, e, *u64) bool` helper alongside foldtointlit. The accepted set mirrors cstage cmd/wcc/check.c:185-208 (fold_int_literal) + :210-284 (eval_enum_value) and harec's enum-resolve constexpr eval at ref/harec/src/check.c:4419-4434: literal leaves (INTLIT/RUNELIT/TRUE/FALSE/NIL), unary +/-/~, binary +/-/*//% & | ^ << >>, and N_IDENT sibling backref bounded by `until` per harec's lnext forward-only-ref discipline (ref/harec/src/check.c:4436-4438). Both N_DOT call sites (inner `EnumT.MEMBER`, outer `pkg.EnumT.MEMBER` via base-resolve) delegate non-literal lhs to enumvalfold instead of bailing. Closes #7. Lands on the A.6.2.1a slot per PLAN.md / Drew's 5-lite plan; subsequent A.6.2.1b-d retire the remaining bail paths before A.6.2.1e enables the assertion. Add test/wcc/759_check_enum_fold.c — table-driven, modelled on 631_def_neg_global.c. 17 rows cover each new shape (INTLIT, RUNELIT, sibling backref, unary +/-/~, all ten binops, chained backref). Exit-code rows pin per-shape fold correctness through both stages (cgen reads the mutated N_INTLIT, so a wrong fold leaks into the constant); asm-byte-id rows pin the symmetric-emit contract between cstage's eval_enum_value and wwstage's enumvalfold. `make sizelint` clean. `make test` green 133/133 (132 pre + new 759).
This commit is contained in:
@@ -7886,6 +7886,89 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
n.tsuffix = empty;
|
||||
};
|
||||
|
||||
// enumvalfold — fold an enum member's value expression to a u64
|
||||
// constant. The Hare-fidelity set: literal leaves, unary +/-/~,
|
||||
// binary arithmetic (+ - * / %), bitwise (& | ^), shifts (<< >>),
|
||||
// and sibling backref. Mirrors cstage cmd/wcc/check.c:185-208
|
||||
// (fold_int_literal) + :210-284 (eval_enum_value); the wider
|
||||
// constexpr evaluator is at ref/harec/src/eval.c (harec resolves
|
||||
// each enum member via eval_expr per ref/harec/src/check.c:4419-
|
||||
// 4434). Wwstage cgen.ww:158-227 (foldintliteral + enumevalmember)
|
||||
// already ships this set for codegen — check now matches.
|
||||
//
|
||||
// `body` is the N_TENUM whose .list is the member chain. `until`
|
||||
// is the member currently being resolved; sibling lookup walks
|
||||
// forward from body.list and stops at `until` to enforce harec's
|
||||
// lnext forward-only-ref discipline (ref/harec/src/check.c:4436-
|
||||
// 4438). `e` starts as that member's lhs and recurses into its
|
||||
// children. Returns false on unfoldable shape, unknown sibling,
|
||||
// or division by zero — callers bail the wrapping N_DOT fold.
|
||||
//
|
||||
// Recursion bound: O(N²) worst case on chained sibling backrefs
|
||||
// (each ident lookup re-walks 0..until). Enum bodies are tiny in
|
||||
// practice — harec accepts the same shape without memoisation per
|
||||
// resolve_enum_field's wrap_resolver chain
|
||||
// (ref/harec/src/check.c:4438) — so the quadratic is harmless.
|
||||
fn enumvalfold(body: *node, until: *node, e: *node, out: *u64) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_TRUE) { *out = 1u64; return true; };
|
||||
if (k == nkind.N_FALSE) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_NIL) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_UN) {
|
||||
let v: u64 = 0u64;
|
||||
if (!enumvalfold(body, until, e.lhs, &v)) { return false; };
|
||||
let op: tkind = e.op;
|
||||
if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; };
|
||||
if (op == tkind.TK_TILDE) { *out = ~v; return true; };
|
||||
if (op == tkind.TK_PLUS) { *out = v; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_BIN) {
|
||||
let a: u64 = 0u64;
|
||||
let b: u64 = 0u64;
|
||||
if (!enumvalfold(body, until, e.lhs, &a)) { return false; };
|
||||
if (!enumvalfold(body, until, e.rhs, &b)) { return false; };
|
||||
let op: tkind = e.op;
|
||||
if (op == tkind.TK_PLUS) { *out = a + b; return true; };
|
||||
if (op == tkind.TK_MINUS) { *out = a - b; return true; };
|
||||
if (op == tkind.TK_STAR) { *out = a * b; return true; };
|
||||
if (op == tkind.TK_SLASH) {
|
||||
if (b == 0u64) { return false; };
|
||||
*out = a / b; return true;
|
||||
};
|
||||
if (op == tkind.TK_PERCENT) {
|
||||
if (b == 0u64) { return false; };
|
||||
*out = a % b; return true;
|
||||
};
|
||||
if (op == tkind.TK_AMP) { *out = a & b; return true; };
|
||||
if (op == tkind.TK_PIPE) { *out = a | b; return true; };
|
||||
if (op == tkind.TK_CARET) { *out = a ^ b; return true; };
|
||||
if (op == tkind.TK_LSHIFT) { *out = a << b; return true; };
|
||||
if (op == tkind.TK_RSHIFT) { *out = a >> b; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_IDENT) {
|
||||
let prev: u64 = (-1i64): u64;
|
||||
let m: *node = body.list;
|
||||
for (m != nil && m != until) {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else {
|
||||
if (!enumvalfold(body, m, m.lhs, &val)) { return false; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) { *out = val; return true; };
|
||||
m = m.next;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// #61 A.5 helper: per-element slot size when `pt` appears inside a
|
||||
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
||||
// spills each element into its own register / 8B eightbyte, so narrow
|
||||
@@ -8613,15 +8696,10 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
// :740-832. Struct field + pseudo-field (.len/.cap/.ptr) lands
|
||||
// in A.6.1.5b. Wwstage has no use_alias (sym.mod disambiguates
|
||||
// — see installdecl docstring at L195-207); SK_USE alone gates
|
||||
// case 1. Enum-member fold here is best-effort: cgen.ww's
|
||||
// enumevalmember covers N_INTLIT + N_IDENT-backref + N_BIN/N_UN,
|
||||
// but every selfhost+lib enum body uses explicit integer
|
||||
// literals (audited 2026-05-21), so the check-side eval stays
|
||||
// N_INTLIT + auto-increment to avoid duplicating cgen's full
|
||||
// const-folder. A non-literal member's lhs makes the auto-
|
||||
// increment prev-tracking unsafe (we'd fold subsequent members
|
||||
// off a wrong base), so we bail rather than guess — cgen's own
|
||||
// N_DOT enum path still resolves the constant.
|
||||
// case 1. Enum-member fold delegates non-literal lhs shapes
|
||||
// (sibling backref, unary, binary, shift) to enumvalfold,
|
||||
// matching cstage cmd/wcc/check.c:210-284 and harec's enum-
|
||||
// resolve constexpr set at ref/harec/src/check.c:4419-4434.
|
||||
let lhsn: *node = e.lhs;
|
||||
if (lhsn != nil) { if (lhsn.kind == nkind.N_IDENT) {
|
||||
let ms: *sym = scopelookupprefer(c.cur, c.curmod, lhsn.str);
|
||||
@@ -8655,11 +8733,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else { if (m.lhs.kind == nkind.N_INTLIT) {
|
||||
val = m.lhs.uval;
|
||||
} else {
|
||||
return nil;
|
||||
}; };
|
||||
if (!enumvalfold(ub, m, m.lhs, &val)) { return nil; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) {
|
||||
foldtointlit(c, e, val: i64);
|
||||
@@ -8690,11 +8766,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else { if (m.lhs.kind == nkind.N_INTLIT) {
|
||||
val = m.lhs.uval;
|
||||
} else {
|
||||
return nil;
|
||||
}; };
|
||||
if (!enumvalfold(bu, m, m.lhs, &val)) { return nil; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) {
|
||||
foldtointlit(c, e, val: i64);
|
||||
|
||||
@@ -922,6 +922,89 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
n.tsuffix = empty;
|
||||
};
|
||||
|
||||
// enumvalfold — fold an enum member's value expression to a u64
|
||||
// constant. The Hare-fidelity set: literal leaves, unary +/-/~,
|
||||
// binary arithmetic (+ - * / %), bitwise (& | ^), shifts (<< >>),
|
||||
// and sibling backref. Mirrors cstage cmd/wcc/check.c:185-208
|
||||
// (fold_int_literal) + :210-284 (eval_enum_value); the wider
|
||||
// constexpr evaluator is at ref/harec/src/eval.c (harec resolves
|
||||
// each enum member via eval_expr per ref/harec/src/check.c:4419-
|
||||
// 4434). Wwstage cgen.ww:158-227 (foldintliteral + enumevalmember)
|
||||
// already ships this set for codegen — check now matches.
|
||||
//
|
||||
// `body` is the N_TENUM whose .list is the member chain. `until`
|
||||
// is the member currently being resolved; sibling lookup walks
|
||||
// forward from body.list and stops at `until` to enforce harec's
|
||||
// lnext forward-only-ref discipline (ref/harec/src/check.c:4436-
|
||||
// 4438). `e` starts as that member's lhs and recurses into its
|
||||
// children. Returns false on unfoldable shape, unknown sibling,
|
||||
// or division by zero — callers bail the wrapping N_DOT fold.
|
||||
//
|
||||
// Recursion bound: O(N²) worst case on chained sibling backrefs
|
||||
// (each ident lookup re-walks 0..until). Enum bodies are tiny in
|
||||
// practice — harec accepts the same shape without memoisation per
|
||||
// resolve_enum_field's wrap_resolver chain
|
||||
// (ref/harec/src/check.c:4438) — so the quadratic is harmless.
|
||||
fn enumvalfold(body: *node, until: *node, e: *node, out: *u64) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_TRUE) { *out = 1u64; return true; };
|
||||
if (k == nkind.N_FALSE) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_NIL) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_UN) {
|
||||
let v: u64 = 0u64;
|
||||
if (!enumvalfold(body, until, e.lhs, &v)) { return false; };
|
||||
let op: tkind = e.op;
|
||||
if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; };
|
||||
if (op == tkind.TK_TILDE) { *out = ~v; return true; };
|
||||
if (op == tkind.TK_PLUS) { *out = v; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_BIN) {
|
||||
let a: u64 = 0u64;
|
||||
let b: u64 = 0u64;
|
||||
if (!enumvalfold(body, until, e.lhs, &a)) { return false; };
|
||||
if (!enumvalfold(body, until, e.rhs, &b)) { return false; };
|
||||
let op: tkind = e.op;
|
||||
if (op == tkind.TK_PLUS) { *out = a + b; return true; };
|
||||
if (op == tkind.TK_MINUS) { *out = a - b; return true; };
|
||||
if (op == tkind.TK_STAR) { *out = a * b; return true; };
|
||||
if (op == tkind.TK_SLASH) {
|
||||
if (b == 0u64) { return false; };
|
||||
*out = a / b; return true;
|
||||
};
|
||||
if (op == tkind.TK_PERCENT) {
|
||||
if (b == 0u64) { return false; };
|
||||
*out = a % b; return true;
|
||||
};
|
||||
if (op == tkind.TK_AMP) { *out = a & b; return true; };
|
||||
if (op == tkind.TK_PIPE) { *out = a | b; return true; };
|
||||
if (op == tkind.TK_CARET) { *out = a ^ b; return true; };
|
||||
if (op == tkind.TK_LSHIFT) { *out = a << b; return true; };
|
||||
if (op == tkind.TK_RSHIFT) { *out = a >> b; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_IDENT) {
|
||||
let prev: u64 = (-1i64): u64;
|
||||
let m: *node = body.list;
|
||||
for (m != nil && m != until) {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else {
|
||||
if (!enumvalfold(body, m, m.lhs, &val)) { return false; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) { *out = val; return true; };
|
||||
m = m.next;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// #61 A.5 helper: per-element slot size when `pt` appears inside a
|
||||
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
||||
// spills each element into its own register / 8B eightbyte, so narrow
|
||||
@@ -1649,15 +1732,10 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
// :740-832. Struct field + pseudo-field (.len/.cap/.ptr) lands
|
||||
// in A.6.1.5b. Wwstage has no use_alias (sym.mod disambiguates
|
||||
// — see installdecl docstring at L195-207); SK_USE alone gates
|
||||
// case 1. Enum-member fold here is best-effort: cgen.ww's
|
||||
// enumevalmember covers N_INTLIT + N_IDENT-backref + N_BIN/N_UN,
|
||||
// but every selfhost+lib enum body uses explicit integer
|
||||
// literals (audited 2026-05-21), so the check-side eval stays
|
||||
// N_INTLIT + auto-increment to avoid duplicating cgen's full
|
||||
// const-folder. A non-literal member's lhs makes the auto-
|
||||
// increment prev-tracking unsafe (we'd fold subsequent members
|
||||
// off a wrong base), so we bail rather than guess — cgen's own
|
||||
// N_DOT enum path still resolves the constant.
|
||||
// case 1. Enum-member fold delegates non-literal lhs shapes
|
||||
// (sibling backref, unary, binary, shift) to enumvalfold,
|
||||
// matching cstage cmd/wcc/check.c:210-284 and harec's enum-
|
||||
// resolve constexpr set at ref/harec/src/check.c:4419-4434.
|
||||
let lhsn: *node = e.lhs;
|
||||
if (lhsn != nil) { if (lhsn.kind == nkind.N_IDENT) {
|
||||
let ms: *sym = scopelookupprefer(c.cur, c.curmod, lhsn.str);
|
||||
@@ -1691,11 +1769,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else { if (m.lhs.kind == nkind.N_INTLIT) {
|
||||
val = m.lhs.uval;
|
||||
} else {
|
||||
return nil;
|
||||
}; };
|
||||
if (!enumvalfold(ub, m, m.lhs, &val)) { return nil; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) {
|
||||
foldtointlit(c, e, val: i64);
|
||||
@@ -1726,11 +1802,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else { if (m.lhs.kind == nkind.N_INTLIT) {
|
||||
val = m.lhs.uval;
|
||||
} else {
|
||||
return nil;
|
||||
}; };
|
||||
if (!enumvalfold(bu, m, m.lhs, &val)) { return nil; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) {
|
||||
foldtointlit(c, e, val: i64);
|
||||
|
||||
@@ -7886,6 +7886,89 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
n.tsuffix = empty;
|
||||
};
|
||||
|
||||
// enumvalfold — fold an enum member's value expression to a u64
|
||||
// constant. The Hare-fidelity set: literal leaves, unary +/-/~,
|
||||
// binary arithmetic (+ - * / %), bitwise (& | ^), shifts (<< >>),
|
||||
// and sibling backref. Mirrors cstage cmd/wcc/check.c:185-208
|
||||
// (fold_int_literal) + :210-284 (eval_enum_value); the wider
|
||||
// constexpr evaluator is at ref/harec/src/eval.c (harec resolves
|
||||
// each enum member via eval_expr per ref/harec/src/check.c:4419-
|
||||
// 4434). Wwstage cgen.ww:158-227 (foldintliteral + enumevalmember)
|
||||
// already ships this set for codegen — check now matches.
|
||||
//
|
||||
// `body` is the N_TENUM whose .list is the member chain. `until`
|
||||
// is the member currently being resolved; sibling lookup walks
|
||||
// forward from body.list and stops at `until` to enforce harec's
|
||||
// lnext forward-only-ref discipline (ref/harec/src/check.c:4436-
|
||||
// 4438). `e` starts as that member's lhs and recurses into its
|
||||
// children. Returns false on unfoldable shape, unknown sibling,
|
||||
// or division by zero — callers bail the wrapping N_DOT fold.
|
||||
//
|
||||
// Recursion bound: O(N²) worst case on chained sibling backrefs
|
||||
// (each ident lookup re-walks 0..until). Enum bodies are tiny in
|
||||
// practice — harec accepts the same shape without memoisation per
|
||||
// resolve_enum_field's wrap_resolver chain
|
||||
// (ref/harec/src/check.c:4438) — so the quadratic is harmless.
|
||||
fn enumvalfold(body: *node, until: *node, e: *node, out: *u64) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_TRUE) { *out = 1u64; return true; };
|
||||
if (k == nkind.N_FALSE) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_NIL) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_UN) {
|
||||
let v: u64 = 0u64;
|
||||
if (!enumvalfold(body, until, e.lhs, &v)) { return false; };
|
||||
let op: tkind = e.op;
|
||||
if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; };
|
||||
if (op == tkind.TK_TILDE) { *out = ~v; return true; };
|
||||
if (op == tkind.TK_PLUS) { *out = v; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_BIN) {
|
||||
let a: u64 = 0u64;
|
||||
let b: u64 = 0u64;
|
||||
if (!enumvalfold(body, until, e.lhs, &a)) { return false; };
|
||||
if (!enumvalfold(body, until, e.rhs, &b)) { return false; };
|
||||
let op: tkind = e.op;
|
||||
if (op == tkind.TK_PLUS) { *out = a + b; return true; };
|
||||
if (op == tkind.TK_MINUS) { *out = a - b; return true; };
|
||||
if (op == tkind.TK_STAR) { *out = a * b; return true; };
|
||||
if (op == tkind.TK_SLASH) {
|
||||
if (b == 0u64) { return false; };
|
||||
*out = a / b; return true;
|
||||
};
|
||||
if (op == tkind.TK_PERCENT) {
|
||||
if (b == 0u64) { return false; };
|
||||
*out = a % b; return true;
|
||||
};
|
||||
if (op == tkind.TK_AMP) { *out = a & b; return true; };
|
||||
if (op == tkind.TK_PIPE) { *out = a | b; return true; };
|
||||
if (op == tkind.TK_CARET) { *out = a ^ b; return true; };
|
||||
if (op == tkind.TK_LSHIFT) { *out = a << b; return true; };
|
||||
if (op == tkind.TK_RSHIFT) { *out = a >> b; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_IDENT) {
|
||||
let prev: u64 = (-1i64): u64;
|
||||
let m: *node = body.list;
|
||||
for (m != nil && m != until) {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else {
|
||||
if (!enumvalfold(body, m, m.lhs, &val)) { return false; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) { *out = val; return true; };
|
||||
m = m.next;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// #61 A.5 helper: per-element slot size when `pt` appears inside a
|
||||
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
||||
// spills each element into its own register / 8B eightbyte, so narrow
|
||||
@@ -8613,15 +8696,10 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
// :740-832. Struct field + pseudo-field (.len/.cap/.ptr) lands
|
||||
// in A.6.1.5b. Wwstage has no use_alias (sym.mod disambiguates
|
||||
// — see installdecl docstring at L195-207); SK_USE alone gates
|
||||
// case 1. Enum-member fold here is best-effort: cgen.ww's
|
||||
// enumevalmember covers N_INTLIT + N_IDENT-backref + N_BIN/N_UN,
|
||||
// but every selfhost+lib enum body uses explicit integer
|
||||
// literals (audited 2026-05-21), so the check-side eval stays
|
||||
// N_INTLIT + auto-increment to avoid duplicating cgen's full
|
||||
// const-folder. A non-literal member's lhs makes the auto-
|
||||
// increment prev-tracking unsafe (we'd fold subsequent members
|
||||
// off a wrong base), so we bail rather than guess — cgen's own
|
||||
// N_DOT enum path still resolves the constant.
|
||||
// case 1. Enum-member fold delegates non-literal lhs shapes
|
||||
// (sibling backref, unary, binary, shift) to enumvalfold,
|
||||
// matching cstage cmd/wcc/check.c:210-284 and harec's enum-
|
||||
// resolve constexpr set at ref/harec/src/check.c:4419-4434.
|
||||
let lhsn: *node = e.lhs;
|
||||
if (lhsn != nil) { if (lhsn.kind == nkind.N_IDENT) {
|
||||
let ms: *sym = scopelookupprefer(c.cur, c.curmod, lhsn.str);
|
||||
@@ -8655,11 +8733,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else { if (m.lhs.kind == nkind.N_INTLIT) {
|
||||
val = m.lhs.uval;
|
||||
} else {
|
||||
return nil;
|
||||
}; };
|
||||
if (!enumvalfold(ub, m, m.lhs, &val)) { return nil; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) {
|
||||
foldtointlit(c, e, val: i64);
|
||||
@@ -8690,11 +8766,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let val: u64 = 0u64;
|
||||
if (m.lhs == nil) {
|
||||
val = prev + 1u64;
|
||||
} else { if (m.lhs.kind == nkind.N_INTLIT) {
|
||||
val = m.lhs.uval;
|
||||
} else {
|
||||
return nil;
|
||||
}; };
|
||||
if (!enumvalfold(bu, m, m.lhs, &val)) { return nil; };
|
||||
};
|
||||
prev = val;
|
||||
if (streq(m.str, e.str)) {
|
||||
foldtointlit(c, e, val: i64);
|
||||
|
||||
Reference in New Issue
Block a user