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:
@@ -181,4 +181,60 @@ mod tests {
|
||||
let sum_def = sum_mod.defs.iter().find(|d| d.name() == "sum").unwrap();
|
||||
assert_eq!(def_hash(sum_def), "db33f57cb329935e");
|
||||
}
|
||||
|
||||
/// Iter 22b.1 regression: adding `Def::Class` and `Def::Instance`
|
||||
/// must NOT change canonical-JSON hashes of any pre-22b def. The
|
||||
/// new variants are alternatives, not field additions — pre-22b
|
||||
/// fixtures simply do not produce a `Class` / `Instance` `Def`,
|
||||
/// and the existing `Fn` / `Const` / `Type` arms are unchanged.
|
||||
/// This re-asserts the same on-disk hashes the 13a / 19b
|
||||
/// regressions pinned, after the 22b.1 schema bump.
|
||||
#[test]
|
||||
fn iter22b1_schema_extension_preserves_pre_22b_hashes() {
|
||||
let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let examples = manifest_dir.join("../../examples");
|
||||
|
||||
let sum_src = std::fs::read(examples.join("sum.ail.json"))
|
||||
.expect("examples/sum.ail.json present");
|
||||
let sum_mod: crate::ast::Module = serde_json::from_slice(&sum_src).unwrap();
|
||||
let sum_def = sum_mod.defs.iter().find(|d| d.name() == "sum").unwrap();
|
||||
assert_eq!(def_hash(sum_def), "db33f57cb329935e");
|
||||
|
||||
let list_src = std::fs::read(examples.join("list.ail.json"))
|
||||
.expect("examples/list.ail.json present");
|
||||
let list_mod: crate::ast::Module = serde_json::from_slice(&list_src).unwrap();
|
||||
let int_list_def = list_mod
|
||||
.defs
|
||||
.iter()
|
||||
.find(|d| d.name() == "IntList")
|
||||
.unwrap();
|
||||
assert_eq!(def_hash(int_list_def), "b082192bd0c99202");
|
||||
}
|
||||
|
||||
/// Iter 22b.1: a [`crate::ast::ClassDef`] with no doc, no
|
||||
/// superclass, and an empty methods list serialises to a stable
|
||||
/// canonical form. Two construction paths (default-elided
|
||||
/// optionals vs. JSON without those keys at all) hash
|
||||
/// bit-identically. If FAIL: a `skip_serializing_if` is missing
|
||||
/// on `superclass` or `doc`, or the parser produces different
|
||||
/// canonical bytes from the same logical value.
|
||||
#[test]
|
||||
fn iter22b1_classdef_empty_optionals_hash_stable() {
|
||||
let bare = Def::Class(crate::ast::ClassDef {
|
||||
name: "Empty".into(),
|
||||
param: "a".into(),
|
||||
superclass: None,
|
||||
methods: vec![],
|
||||
doc: None,
|
||||
});
|
||||
|
||||
let json = r#"{"kind":"class","name":"Empty","param":"a","methods":[]}"#;
|
||||
let parsed: Def = serde_json::from_str(json).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
def_hash(&bare),
|
||||
def_hash(&parsed),
|
||||
"ClassDef with elided optionals must hash identically to construction with explicit None"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user