iter 22b.2.10: fix — positive green-path test, drop dead let _ = ws
Adds the missing positive counterpart to the no-instance test: `show 42` with `instance Show Int` PRESENT must typecheck green. This guards against registry-keying or threading bugs that would otherwise sneak past the negative-only test (an empty registry at typecheck time, or a key shape mismatch, would silently fire no-instance even when the instance exists). Also drops the dead `let _ = ws;` and its stale comment in `check_in_workspace` — the line above already consumes `ws.registry`, so the explicit drop is redundant. The remaining comment is folded into the registry-threading comment so the "registry is the only thing threaded" rationale is preserved.
This commit is contained in:
@@ -235,3 +235,26 @@ fn fn_calling_class_method_at_type_without_instance_fires_no_instance() {
|
||||
diagnostics.iter().map(|d| &d.code).collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
/// Property protected: the positive counterpart to `no-instance` — when a
|
||||
/// monomorphic fn calls a class method at a fully-concrete type AND a
|
||||
/// matching `instance C T` exists in the workspace, the call typechecks
|
||||
/// green. The concrete-residual path must look up `(class, type_hash(T))`
|
||||
/// in `env.workspace_registry` and find a hit, so no diagnostic fires.
|
||||
/// This guards against registry-keying or threading bugs that would
|
||||
/// otherwise sneak past the negative-only test: a registry that is empty
|
||||
/// at typecheck time, or keyed under the wrong shape, would silently fire
|
||||
/// `no-instance` even when the instance is present. Fixture: `main` calls
|
||||
/// `show 42` with `instance Show Int` declared in the same workspace.
|
||||
#[test]
|
||||
fn fn_calling_class_method_at_type_with_instance_typechecks_green() {
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
diagnostics.is_empty(),
|
||||
"expected no diagnostics — instance Show Int is present, registry lookup must hit; got: {:?}",
|
||||
diagnostics
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1177,12 +1177,11 @@ fn check_in_workspace(
|
||||
env.class_superclasses = class_superclasses;
|
||||
// Iter 22b.2 (Task 10): thread the workspace-load-time instance
|
||||
// registry into the env so `check_fn`'s concrete-residual path can
|
||||
// look up `(class, type_hash)` keys for the no-instance check.
|
||||
// look up `(class, type_hash)` keys for the no-instance check. The
|
||||
// registry is the only field of `ws` consumed at typecheck time;
|
||||
// cross-module name resolution uses `module_globals` / `module_types`
|
||||
// built earlier in this function.
|
||||
env.workspace_registry = ws.registry.clone();
|
||||
// Workspace isn't otherwise needed in the env; cross-module lookup
|
||||
// uses only `module_globals` / `module_types`. The ws reference is
|
||||
// preserved in case cross-module ADTs are added later.
|
||||
let _ = ws;
|
||||
|
||||
for def in &m.defs {
|
||||
if let Err(e) = check_def(def, &env) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "test_22b2_instance_present",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "class", "name": "Show", "param": "a",
|
||||
"methods": [{
|
||||
"name": "show",
|
||||
"type": {
|
||||
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
||||
"ret": { "k": "con", "name": "Str" }, "effects": []
|
||||
}
|
||||
}]
|
||||
},
|
||||
{
|
||||
"kind": "instance",
|
||||
"class": "Show",
|
||||
"type": { "k": "con", "name": "Int" },
|
||||
"methods": [{
|
||||
"name": "show",
|
||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "n" } }
|
||||
}]
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "main",
|
||||
"type": {
|
||||
"k": "fn", "params": [], "ret": { "k": "con", "name": "Str" },
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "show" },
|
||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user