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:
@@ -195,6 +195,12 @@ pub fn emit_ir(m: &Module) -> Result<String> {
|
||||
entry: m.name.clone(),
|
||||
modules,
|
||||
root_dir: std::path::PathBuf::from("."),
|
||||
// Iter 22b.1: emit_ir is the single-module shortcut. The
|
||||
// empty registry is fine for 22b.1 because codegen does not
|
||||
// yet read it; once 22b.3 monomorphisation runs, the queue
|
||||
// is built from class-method-call sites in already-typechecked
|
||||
// module bodies, not from the registry.
|
||||
registry: ailang_core::workspace::Registry::default(),
|
||||
};
|
||||
lower_workspace(&ws)
|
||||
}
|
||||
@@ -251,6 +257,11 @@ fn lower_workspace_inner(ws: &Workspace, alloc: AllocStrategy) -> Result<String>
|
||||
.map(|(k, m)| (k.clone(), ailang_core::desugar::desugar_module(m)))
|
||||
.collect(),
|
||||
root_dir: ws.root_dir.clone(),
|
||||
// Iter 22b.1: pass the registry through unchanged. The desugar
|
||||
// pass does not touch class/instance defs (see desugar.rs:
|
||||
// 22b.1 passthrough), so the registry built at load time
|
||||
// remains valid against the desugared modules.
|
||||
registry: ws.registry.clone(),
|
||||
};
|
||||
let ws = &ws_owned;
|
||||
let mut header = String::new();
|
||||
@@ -2837,6 +2848,7 @@ mod tests {
|
||||
x
|
||||
},
|
||||
root_dir: std::path::PathBuf::from("."),
|
||||
registry: ailang_core::workspace::Registry::default(),
|
||||
};
|
||||
let ir_rc = lower_workspace_with_alloc(&ws, AllocStrategy::Rc).unwrap();
|
||||
assert!(
|
||||
|
||||
Reference in New Issue
Block a user