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:
@@ -968,6 +968,67 @@ fn workspace_error_to_diagnostic(
|
||||
"module": name,
|
||||
})),
|
||||
),
|
||||
// Iter 22b.1: typeclass-coherence diagnostics emitted from
|
||||
// `workspace::build_registry`. The codes follow the JOURNAL
|
||||
// queue's wording and Decision 11 §"Diagnostic categories".
|
||||
W::OrphanInstance {
|
||||
class,
|
||||
type_repr,
|
||||
defining_module,
|
||||
class_module,
|
||||
type_module,
|
||||
} => Some(
|
||||
ailang_check::Diagnostic::error(
|
||||
"orphan-instance",
|
||||
format!(
|
||||
"orphan instance: `instance {class} {type_repr}` declared in `{defining_module}`, \
|
||||
but neither `{class}` (in `{class_module}`) nor `{type_repr}` (in `{type_module}`) lives there"
|
||||
),
|
||||
)
|
||||
.with_ctx(serde_json::json!({
|
||||
"class": class,
|
||||
"type": type_repr,
|
||||
"defining_module": defining_module,
|
||||
"class_module": class_module,
|
||||
"type_module": type_module,
|
||||
})),
|
||||
),
|
||||
W::DuplicateInstance {
|
||||
class,
|
||||
type_repr,
|
||||
first_module,
|
||||
second_module,
|
||||
} => Some(
|
||||
ailang_check::Diagnostic::error(
|
||||
"duplicate-instance",
|
||||
format!(
|
||||
"duplicate instance: `instance {class} {type_repr}` declared in both `{first_module}` and `{second_module}`"
|
||||
),
|
||||
)
|
||||
.with_ctx(serde_json::json!({
|
||||
"class": class,
|
||||
"type": type_repr,
|
||||
"first_module": first_module,
|
||||
"second_module": second_module,
|
||||
})),
|
||||
),
|
||||
W::MissingMethod {
|
||||
class,
|
||||
type_repr,
|
||||
method,
|
||||
} => Some(
|
||||
ailang_check::Diagnostic::error(
|
||||
"missing-method",
|
||||
format!(
|
||||
"instance `{class} {type_repr}` is missing a body for method `{method}` (no default)"
|
||||
),
|
||||
)
|
||||
.with_ctx(serde_json::json!({
|
||||
"class": class,
|
||||
"type": type_repr,
|
||||
"method": method,
|
||||
})),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1854,6 +1915,11 @@ fn build_to(
|
||||
entry: ws.entry.clone(),
|
||||
modules: lifted_modules,
|
||||
root_dir: ws.root_dir.clone(),
|
||||
// Iter 22b.1: pass the registry through the lift pass. Lift
|
||||
// only rewrites `Term::LetRec` into top-level fns; it does
|
||||
// not touch class/instance defs, so the registry built at
|
||||
// load-time remains valid.
|
||||
registry: ws.registry.clone(),
|
||||
};
|
||||
let ir = ailang_codegen::lower_workspace_with_alloc(&ws, alloc)?;
|
||||
let tmpdir = std::env::temp_dir().join(format!("ailang-{}", std::process::id()));
|
||||
|
||||
Reference in New Issue
Block a user