6.7 KiB
iter ctt.2 — Registry.type_def_module re-key to tuple-keyed map
Date: 2026-05-12
Started from: 548ebf8d51
Status: DONE
Tasks completed: 3 of 3
Summary
Registry.type_def_module re-keyed from BTreeMap<String, String> to
BTreeMap<(String, String), String> keyed by (owning_module, bare_name). A new caller_module: &str parameter threads through
normalize_type_for_registry and Registry::normalize_type_for_lookup,
and all four ailang-check consumer sites pass the correct
module-context per the plan's Design Notes block. A regression test
plus a three-module fixture exercise the bare-name collision the
re-key fixes — two modules each declaring type Foo now register
under distinct canonical keys instead of tripping the silent-overwrite
defect. cargo test --workspace green (16 binary-test suites,
~600 tests total, zero failures).
Per-task notes
- iter ctt.2.1: RED-first — three fixture JSON files
(
ctt2_collision_{cls,lib,main}.ail.json) pluscrates/ailang-core/tests/ctt2_registry_rekey.rs. Test goes RED today. Failure shape wasOrphanInstancerather than the plan's predictedDuplicateInstance(a) or missing-hash (b) — see Concerns. - iter ctt.2.2: GREEN — atomic re-key edit pass. Touched the field
type + doc-comment,
Registry::normalize_type_for_lookupsignature + body, pass-1 declaration + insert, pass-2 coherence-check lookup + canonical-form hashing call,normalize_type_for_registrysignature + doc-comment + body (recursive calls thread caller_module everywhere), the inlinect1_5a_normalize_recurses_into_forall_constraintstest at workspace.rs:2543, and all fourailang-checkconsumer sites at the module-context dictated by the plan's Design Notes (lib.rs:1640 →env.current_module.as_str(), mono.rs:121 →defining_module.as_str(), mono.rs:624 and :1175 →module_name). Cleancargo build --workspaceat the end of the pass. - iter ctt.2.3: workspace-wide test gate. New test goes GREEN.
Full
cargo test --workspacegreen, no test in any crate regressed. The plan's Step 2 hypothesis ("a fixture underexamples/might legitimately exercise a bare cross-module type reference") did not materialise — the existing corpus uses canonical-form (qualified) cross-module type refs exclusively, so the tightening had no surface.
Concerns
-
Task 1 RED-failure shape diverged from the plan's predicted shapes (a)
DuplicateInstanceand (b) missing-contains_key. The plan's verbatim two-module fixture pair (lib imports main + main imports lib + lib-side instance with qualified classctt2_collision_main.MyC) had two independent structural defects against the loaded codebase invariants:- The workspace loader rejects import cycles
(
WorkspaceLoadError::Cycle) at module-name granularity — the plan's claim "Two-way import is supported; workspace loader DFS handles cycles at module-name granularity" is empirically false. Confirmed by inspection atworkspace.rs:1410-1413and:1451-1454. validate_canonical_type_namesrejects qualifiedInstanceDef.classwithQualifiedClassName(see testct1_validator_rejects_qualified_instancedef_classat workspace.rs:2321) — the plan's lib-side instance withclass: "ctt2_collision_main.MyC"would have been rejected even without the cycle.
Implementer-phase repair: introduced a third module
ctt2_collision_cls.ail.jsoncarryingclass MyC, broke the cycle (both lib and main import cls only; main also imports lib so the loader DFS reaches it), and dropped the qualifier from both instance heads (both declare bareclass: "MyC"satisfying coherence via the type's module). The plan's core RED-condition is preserved: two modules each declaringtype Foowithinstance MyC Foocollide on the pre-ctt.2 bare-nametype_def_modulekey.The actually-observed RED shape was
OrphanInstancerather thanDuplicateInstancebecause the pass-2 coherence check (workspace.rs:656-659) uses the bare-name lookup before the duplicate-uniqueness check fires — lib'sFooand main'sFooboth resolve to whichever module won the alphabetical race (ctt2_collision_mainbeatsctt2_collision_liblexicographically), so lib's instance is no longer coherent ("type lives in main, class lives in cls, instance lives in lib — neither matches"). The re-key fixes this consumer site simultaneously with the duplicate-check site because both go through the sametype_def_modulelookup, now tuple-keyed.The deviation from the plan's verbatim fixtures is an implementer-phase NEEDS_CONTEXT repair that the user-no-stop-instruction permitted in-line; the plan's intent (RED-first against the bare-name collision) is achieved and the GREEN-state matches the plan's acceptance criteria unchanged. Boss may want to back-edit the plan or amend the spec to note the multi-module fixture shape if this kind of collision regression returns later.
- The workspace loader rejects import cycles
(
Known debt
- The
OrphanInstanceconsumer site atworkspace.rs:656-659is fixed by ctt.2 but the diagnostic-shape change (orphan instead of duplicate-on-loser) is not separately tested. The new test asserts the GREEN state directly (both entries land under distinct keys) which transitively exercises both consumer sites, but neither the orphan nor the duplicate diagnostic shapes are pinned by a dedicated RED test. Adding one is plausibly out-of-scope for ctt.2.
Files touched
Modified (3):
crates/ailang-check/src/lib.rs— single call-site update at the NoInstance check insidecheck_fn.crates/ailang-check/src/mono.rs— three call-site updates (monomorphise_workspace at :121, collect_mono_targets at :624, collect_residuals_ordered at :1175).crates/ailang-core/src/workspace.rs— field re-key,Registry::normalize_type_for_lookupsignature,normalize_type_for_registrysignature + body, pass-1 declaration + insert, pass-2 coherence-check lookup + canonical-form hashing call, inline testct1_5a_normalize_recurses_into_forall_constraintsat :2543; doc-comments at field-decl and at bothnormalize_…fns.
Added (4):
crates/ailang-core/tests/ctt2_registry_rekey.rs— regression test.examples/ctt2_collision_cls.ail.json— class-bearing module (not in plan; required to break the cycle in the plan's verbatim fixture design).examples/ctt2_collision_lib.ail.json—type Foo = MkLib+ bareinstance MyC Foo.examples/ctt2_collision_main.ail.json—type Foo = MkMain+ bareinstance MyC Foo, plus imports of bothclsandlib.
Stats
bench/orchestrator-stats/2026-05-12-iter-ctt.2.json