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).
8.6 KiB
8.6 KiB