Section 02: Evaluator Algorithmic DRY
Status: Not Started
Goal: Extract shared control-flow skeletons into canonical helpers. Eliminate the 9-way iterator consumer duplication, 8-way Option/Result handler duplication, and 3-way iterator method name list duplication.
Context: The evaluator has the most algorithmic duplication of any crate. Nine iterator consumers share an identical loop { eval_iter_next → match Some/None } skeleton. Eight Option/Result method handlers share an identical validate → extract → call closure → wrap skeleton. Iterator method names are maintained in 3 independent lists that must be manually kept in sync.
02.1 Extract Iterator Consumer Drive Function
File(s): compiler/ori_eval/src/interpreter/method_dispatch/iterator/consumers.rs
Nine functions share identical loop harness: eval_iter_fold, eval_iter_count, eval_iter_find, eval_iter_any, eval_iter_all, eval_iter_for_each, eval_iter_collect, eval_iter_collect_set, eval_iter_join.
-
Create
drive_iterator()method on Interpreter:fn drive_iterator<A, F>( &mut self, iter_val: IteratorValue, init: A, mut step: F, ) -> EvalResult<A> where F: FnMut(&mut Self, A, Value) -> EvalResult<ControlFlow<A, A>>, -
Rewrite all 9 consumers using
drive_iterator()(fold, count, find, any, all, for_each, collect, collect_set, join)- [ ] Verify each consumer still produces identical results (existing tests) -
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (02.1) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-02.1 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 02.1: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
02.2 Extract Option/Result Method Handler
File(s): compiler/ori_eval/src/interpreter/method_dispatch/collection_ops.rs
Eight functions share the pattern: validate arg count, match receiver variant, call closure on inner value, wrap result. These are: eval_option_map, eval_option_and_then, eval_option_filter, eval_option_or_else, eval_result_map, eval_result_map_err, eval_result_and_then, eval_result_or_else.
-
Create a generic handler parameterized by:
- Which variant to match (Some/Ok/Err)
- What to do with the inner value (call closure, call predicate)
- How to wrap the result (Some, Ok, Err, identity)
- WHERE:
compiler/ori_eval/src/interpreter/method_dispatch/collection_ops.rslines 379-491
-
Note: the 8 handlers use inconsistent arg validation — some use
wrong_arg_count(), some useSelf::expect_arg_count(). Unify to a single pattern during extraction.- [ ] Rewrite the 8 functions using the shared handler -
Verify all existing tests pass unchanged
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (02.2) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-02.2 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 02.2: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
02.3 Unify Iterator Method Name Lists
File(s): compiler/ori_eval/src/methods/dispatch_check.rs (line 66: is_collection_dispatched()), compiler/ori_eval/src/interpreter/resolvers/collection/mod.rs (line ~110: resolve_iterator_method() if-chain), compiler/ori_eval/src/interpreter/resolvers/mod.rs (line 213: all_iterator_variants())
Three independent lists enumerate iterator methods: CollectionMethod::all_iterator_variants() (in resolvers/mod.rs), CollectionMethodResolver::resolve_iterator_method() (if-chain in resolvers/collection/mod.rs), and dispatch_check::is_collection_dispatched() (in methods/dispatch_check.rs). Note: there are already enforcement tests in resolvers/tests.rs that validate all_iterator_variants() against is_iterator_method() — the goal here is to extend this pattern to cover dispatch_check too, and ideally derive the routing from the canonical list.
-
Make
resolve_iterator_method()derive its routing fromall_iterator_variants()— use a lookup map built from the canonical list -
Make
is_collection_dispatched()derive fromall_iterator_variants()— check membership in the same lookup map -
Add an enforcement test:
all_iterator_variants().iter().all(|(name, _)| is_collection_dispatched(name)) -
Verify: adding a new iterator method to
all_iterator_variants()is the ONLY change needed (routing and dispatch check are derived) -
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (02.3) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-02.3 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 02.3: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
02.4 Eliminate Redundant Name Interning
File(s): compiler/ori_eval/src/interpreter/derived_methods.rs, compiler/ori_eval/src/interpreter/interned_names.rs, compiler/ori_eval/src/methods/names.rs
-
Merge overlapping entries between
OpNamesandBuiltinMethodNames— shared names (“add”, “compare”, “bit_and”, etc.) should be interned once -
Replace
self.interner.intern("to_str")informat_value_printable()(line 376 ofderived_methods.rs) withself.builtin_method_names.to_str(already available — seeconsumers.rs:202which uses it correctly)- [ ] Replaceself.interner.intern("default")ineval_default_construct()(lines 446, 484 ofderived_methods.rs) with a pre-interned name — adddefaulttoBuiltinMethodNamesininterned_names.rsif not already present- [ ] Verify no runtime interning of known-at-startup method names remains inderived_methods.rs:grep -n 'interner\.intern\|\.intern(' compiler/ori_eval/src/interpreter/derived_methods.rsreturns 0 matches -
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (02.4) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-02.4 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 02.4: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
Cleanup (fix while touching these files)
- [WASTE]
compiler/ori_eval/src/interpreter/method_dispatch/collection_ops.rs— 8 Option/Result handlers useunreachable!("...")without structured context; replace withunreachable!("eval_option_map dispatched on {receiver:?}")to aid debugging on panic - [WASTE]
compiler/ori_eval/src/interpreter/method_dispatch/collection_ops.rs:130-136—then_witharg check uses inlineEvalError::new(format!(...))instead ofwrong_arg_count("then_with", 1, args.len())error factory; inconsistent with rest of file
02.R Third Party Review Findings
- None.
02.T Test Strategy
This section is pure structural refactoring with zero behavioral change. The test strategy focuses on:
- Existing test suite as regression gate:
./test-all.shmust pass identically before and after each sub-section. - Unit tests for new canonical functions: Each extracted function gets direct unit tests.
- Enforcement tests for method name canonical source: Verify all consumers derive from the single list.
- Add unit tests for
drive_iterator()incompiler/ori_eval/src/interpreter/method_dispatch/iterator/tests.rs:- Empty iterator produces init value unchanged
ControlFlow::Breakstops iteration early and returns the break valueControlFlow::Continueprocesses all elements- Test with a 3-element iterator to verify ordering (first, second, third)
- Add unit tests for the Option/Result shared handler:
Some(v)with identity closure returnsSome(v)Nonewith any closure returnsNoneOk(v)maps correctly;Err(e)passes through unchanged (and vice versa formap_err)
- Add enforcement test:
all_iterator_variants()entries are all present inis_collection_dispatched() - Verify
timeout 150 cargo test -p ori_evalpasses after each sub-section - Verify
timeout 150 ./test-all.shpasses after all sub-sections complete
02.N Completion Checklist
-
drive_iterator()extracted — 9 consumers use it - Option/Result handler extracted — 8 functions use it
- Iterator method name lists reduced to 1 canonical source
- No runtime interning of known method names in derived_methods.rs
- Unit tests for all new canonical functions pass
- Enforcement test for iterator method name derivation passes
-
timeout 150 cargo test -p ori_evalpasses -
timeout 150 ./test-all.shpasses -
./clippy-all.shclean -
/tpr-reviewcovering Section 02 -
/impl-hygiene-review -
/improve-toolingretrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (whichdiagnostics/scripts you ran, which command sequences you repeated, where you added ad-hocdbg!/tracingcalls, where output was hard to interpret) and identify any tool/log/diagnostic improvement that would have made this section materially easier OR that would help the next section touching this area. Implement every accepted improvement NOW (zero deferral) and commit each via SEPARATE/commit-push. The retrospective is mandatory even when nothing felt painful — that is exactly when blind spots accumulate. See.claude/skills/improve-tooling/SKILL.md“Retrospective Mode” for the full protocol.