iter 22b.1.2: workspace registry skeleton + coherence checks

Adds the workspace-global typeclass instance registry per Decision 11
"Resolution and monomorphisation". Built at the end of load_workspace
after the DFS over imports completes; keyed by (class-name, type-hash)
where type-hash uses the new canonical::type_hash (16-hex prefix,
parallel to def_hash and module_hash).

Three coherence checks fire from build_registry, each surfacing as a
distinct WorkspaceLoadError variant:

- OrphanInstance: `instance C T` not in C's or T's defining module.
- DuplicateInstance: two entries share the same (class, type-hash) key.
- MissingMethod: instance omits a required (non-default) method.

The CLI's workspace_error_to_diagnostic is extended with the three new
codes (orphan-instance / duplicate-instance / missing-method).

All existing Workspace { ... } construction sites get the new
`registry` field, defaulting to Registry::default() at synthetic /
test-only paths and threading through ws.registry.clone() at codepath
sites that already hold a real workspace.

Includes hash-stability regression tests (iter22b1_schema_extension_*
and iter22b1_classdef_empty_optionals_hash_stable) and the empty-
registry positive test against examples/sum.ail.json. Test count:
288 → 291 (3 new tests, all pass).
This commit is contained in:
2026-05-09 12:37:00 +02:00
parent f25d7b6cd6
commit eb4db9dafc
8 changed files with 442 additions and 2 deletions
+6
View File
@@ -1388,6 +1388,7 @@ fn reuse_as_demo_under_rc_uses_inplace_rewrite() {
entry: ws.entry.clone(),
modules: lifted_modules,
root_dir: ws.root_dir.clone(),
registry: ws.registry.clone(),
};
let ir = ailang_codegen::lower_workspace_with_alloc(
&lifted_ws,
@@ -1586,6 +1587,7 @@ fn alloc_rc_borrow_only_recursive_list_drop() {
entry: ws.entry.clone(),
modules: lifted_modules,
root_dir: ws.root_dir.clone(),
registry: ws.registry.clone(),
};
let ir = ailang_codegen::lower_workspace_with_alloc(
&lifted_ws,
@@ -1661,6 +1663,7 @@ fn alloc_rc_partial_drop_skips_moved_keeps_wildcarded() {
entry: ws.entry.clone(),
modules: lifted_modules,
root_dir: ws.root_dir.clone(),
registry: ws.registry.clone(),
};
let ir = ailang_codegen::lower_workspace_with_alloc(
&lifted_ws,
@@ -1750,6 +1753,7 @@ fn alloc_rc_own_param_dec_at_fn_return() {
entry: ws.entry.clone(),
modules: lifted_modules,
root_dir: ws.root_dir.clone(),
registry: ws.registry.clone(),
};
let ir = ailang_codegen::lower_workspace_with_alloc(
&lifted_ws,
@@ -1875,6 +1879,7 @@ fn iter18e_drop_iterative_emits_worklist_body_no_self_recursion() {
entry: ws.entry.clone(),
modules: lifted_modules,
root_dir: ws.root_dir.clone(),
registry: ws.registry.clone(),
};
let ir = ailang_codegen::lower_workspace_with_alloc(
&lifted_ws,
@@ -1958,6 +1963,7 @@ fn iter18e_no_annotation_keeps_recursive_drop_body() {
entry: ws.entry.clone(),
modules,
root_dir: ws.root_dir.clone(),
registry: ws.registry.clone(),
};
let ir = ailang_codegen::lower_workspace_with_alloc(
&lifted_ws,