Section 04: Type Resolution DRY
Status: Not Started
Goal: The 6+ ParsedType resolution functions (resolve_parsed_type_simple, resolve_type_with_params, resolve_type_with_self/resolve_type_with_self_inner, resolve_and_check_type_with_vars, resolve_parsed_type, resolve_parsed_type_list) share an identical match-on-variant structure. Extract the shared tree walk into a generic resolver parameterized by how to handle type variables, Self, and unknown names.
Context: This is the most severe algorithmic duplication in the type checker. All 5 functions walk the same ParsedType enum (Primitive, List, Map, Tuple, Function, Named, etc.) with identical recursive structure, differing only in: (a) how type parameters are resolved (fresh vars, lookup, error), (b) how Self is handled (fresh var, lookup, error), (c) whether to validate bounds. Additionally, dual string/Name well-known type tables create 2 more duplication sites.
04.1 Design TypeResolver Trait
File(s): compiler/ori_types/src/check/registration/type_resolution.rs, compiler/ori_types/src/check/signatures/mod.rs, compiler/ori_types/src/infer/expr/type_resolution.rs
Implementation note: The resolution functions operate on two different context types (ModuleChecker vs InferEngine). The shared trait must abstract pool_mut(), interner(), resolve_well_known_generic_cached(), and resolve_registration_primitive(). The InferEngine version handles additional variants (FixedList, Option, Result, Set, AssociatedType, ExistentialType, ConstGeneric) that the ModuleChecker ones do not.
-
Design a
TypeResolveContexttrait that abstracts:pool_mut() -> &mut Pool— access to type pool (both ModuleChecker and InferEngine have this)interner() -> &StringInterner— name interningresolve_well_known_generic(name: Name, args: &[Idx]) -> Option<Idx>— well-known type lookupresolve_registration_primitive(name: Name) -> Option<Idx>— primitive name resolution
-
Design a
ResolveConfigstruct that parameterizes:resolve_type_param(name: Name) -> Idx— how to handle type parametersresolve_self() -> Idx— how to handle Self typeresolve_unknown_name(name: Name) -> Idx— fresh var vs Idx::ERRORcheck_bounds: bool— whether to validate trait bounds
-
Implement
resolve_parsed_type_with<C: TypeResolveContext>()as the single canonical tree walk -
Handle the variant coverage gap: the InferEngine version handles FixedList, Option, Result, Set, AssociatedType, ExistentialType, ConstGeneric — these MUST be supported in the canonical function (likely as optional handlers in the config)
-
Rewrite all 6+ existing functions as thin wrappers that construct the appropriate config and call the canonical function (including
resolve_type_with_self,resolve_parsed_type_list)- [ ] Verify: the canonical function handles ALLParsedTypevariants (Primitive, List, FixedList, Map, Tuple, Function, Named, Option, Result, Set, TraitBounds, SelfType, AssociatedType, ExistentialType, ConstGeneric, etc.) -
Verify: all existing type checker 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 (04.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-04.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 04.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.
04.2 Unify Well-Known Type Tables
File(s): compiler/ori_types/src/check/well_known/mod.rs
Two pairs of functions encode the same tables in both string and Name forms: resolve_well_known_generic() (string) / WellKnownNames::resolve_generic() (Name), and is_concrete_named_type() (string) / WellKnownNames::is_concrete() (Name).
-
WHERE:
compiler/ori_types/src/check/well_known/mod.rs— findresolve_well_known_generic()(string-based) and correspondingWellKnownNames::resolve_generic()(Name-based); also findis_concrete_named_type()andWellKnownNames::is_concrete() -
Make the string-based versions derive from the Name-based versions: string function interns the string, then delegates to the Name-based function. This ensures one canonical table.- [ ] If WellKnownNames is not always available (e.g., in isolated tests), provide a
from_str()lookup that maps through interning rather than maintaining a parallel table -
Verify: adding a new well-known type requires updating exactly ONE location — add a test that the string-based and Name-based tables produce identical results for all entries
-
/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 (04.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-04.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 04.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.
04.3 Add Unit/Never TypeDefs to Registry
File(s): compiler/ori_registry/src/defs/, compiler/ori_types/src/check/well_known/trait_set.rs, compiler/ori_types/src/infer/expr/registry_bridge/mod.rs
Unit and Never have no TypeDef in ori_registry, forcing hardcoded trait satisfaction fallbacks in ori_types at 3+ locations.
-
Add
TypeDeffor Unit inori_registrywith traits: Eq, Comparable, Hashable, Clone, Default, Debug, Printable -
Add
TypeDeffor Never inori_registrywith appropriate traits -
Remove hardcoded Unit trait satisfaction from
trait_set.rs:229-236 -
Remove hardcoded Unit/Never fallbacks from
registry_bridge/mod.rs:65-75 -
Verify:
registry_satisfies_trait()correctly resolves Unit and Never traits via registry query -
WARNING: Adding TypeDefs for Unit/Never changes how trait satisfaction is resolved for these types. Run
timeout 150 cargo stto verify all spec tests pass — any test involvingvoidorNevertypes could break if the trait set is wrong. -
/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 (04.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-04.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 04.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.
04.R Third Party Review Findings
- None.
04.T Test Strategy
This section refactors the most complex compiler subsystem (type resolution). Zero behavioral change, but high risk of subtle breakage.
- Before any code changes: Snapshot the current
timeout 150 cargo stoutput to detect any behavioral drift - Add unit tests for
resolve_parsed_type_with()covering allParsedTypevariants:- Primitive (int, float, str, bool, char, byte, void)
- List, FixedList, Map, Tuple, Function
- Named (user types, well-known generics)
- Option, Result, Set
- SelfType (with and without Self in scope)
- AssociatedType, ExistentialType, ConstGeneric
- TraitBounds
- Each variant tested with each
ResolveConfigmode (fresh vars, lookup, error)
- Add enforcement test: well-known type string table and Name table produce identical results for all entries
- Add enforcement test: Unit and Never trait satisfaction via registry matches the previous hardcoded behavior exactly
- Verify
timeout 150 cargo test -p ori_typespasses after each sub-section (04.1, 04.2, 04.3) - Verify
timeout 150 cargo stoutput is byte-identical to pre-change snapshot - Verify
timeout 150 ./test-all.shpasses after all sub-sections complete
04.N Completion Checklist
- Single canonical
resolve_parsed_type_with()function - 6+ existing resolution functions are thin wrappers
- Well-known type tables have single source (not dual string/Name)
- Unit and Never have TypeDefs in ori_registry
- No hardcoded trait satisfaction for Unit/Never in ori_types
- Unit tests for canonical resolver cover all ParsedType variants x ResolveConfig modes
- Enforcement tests for well-known tables and Unit/Never trait sets
-
timeout 150 cargo test -p ori_typespasses -
timeout 150 cargo test -p ori_registrypasses -
timeout 150 ./test-all.shpasses -
./clippy-all.shclean -
/tpr-reviewcovering Section 04 -
/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.