diff --git a/crates/ailang-core/src/workspace.rs b/crates/ailang-core/src/workspace.rs index 061295d..cf4484b 100644 --- a/crates/ailang-core/src/workspace.rs +++ b/crates/ailang-core/src/workspace.rs @@ -2557,4 +2557,54 @@ mod tests { other => panic!("expected QualifiedClassName, got {other:?}"), } } + + /// ct.1: on-disk fixture for `BareCrossModuleTypeRef`. Bare + /// `Ordering` Term::Ctor with no imports; the validator catches it + /// after prelude injection (so the candidate list contains + /// `prelude.Ordering`). + #[test] + fn ct1_fixture_bare_xmod_rejected() { + let entry = examples_dir().join("test_ct1_bare_xmod_rejected.ail.json"); + let err = load_workspace(&entry).expect_err("must reject bare Ordering"); + match err { + WorkspaceLoadError::BareCrossModuleTypeRef { module, name, candidates } => { + assert_eq!(module, "test_ct1_bare_xmod_rejected"); + assert_eq!(name, "Ordering"); + assert_eq!(candidates, vec!["prelude.Ordering".to_string()]); + } + other => panic!("expected BareCrossModuleTypeRef, got {other:?}"), + } + } + + /// ct.1: on-disk fixture for `BadCrossModuleTypeRef`. Qualified + /// `Mystery.Type` with `Mystery` not a known module. + #[test] + fn ct1_fixture_bad_qualifier() { + let entry = examples_dir().join("test_ct1_bad_qualifier.ail.json"); + let err = load_workspace(&entry).expect_err("must reject Mystery.Type"); + match err { + WorkspaceLoadError::BadCrossModuleTypeRef { module, name } => { + assert_eq!(module, "test_ct1_bad_qualifier"); + assert_eq!(name, "Mystery.Type"); + } + other => panic!("expected BadCrossModuleTypeRef, got {other:?}"), + } + } + + /// ct.1: on-disk fixture for `QualifiedClassName`. Qualified + /// `prelude.Eq` in an `InstanceDef.class` field — the schema + /// rejects this so half-migrated files cannot silently load. + #[test] + fn ct1_fixture_qualified_class_rejected() { + let entry = examples_dir().join("test_ct1_qualified_class_rejected.ail.json"); + let err = load_workspace(&entry).expect_err("must reject prelude.Eq"); + match err { + WorkspaceLoadError::QualifiedClassName { module, name, field } => { + assert_eq!(module, "test_ct1_qualified_class_rejected"); + assert_eq!(name, "prelude.Eq"); + assert_eq!(field, "InstanceDef.class"); + } + other => panic!("expected QualifiedClassName, got {other:?}"), + } + } } diff --git a/examples/test_ct1_bad_qualifier.ail.json b/examples/test_ct1_bad_qualifier.ail.json new file mode 100644 index 0000000..a02d4a1 --- /dev/null +++ b/examples/test_ct1_bad_qualifier.ail.json @@ -0,0 +1,19 @@ +{ + "schema": "ailang/v0", + "name": "test_ct1_bad_qualifier", + "imports": [], + "defs": [ + { + "kind": "fn", + "name": "f", + "type": { + "k": "fn", + "params": [], + "ret": { "k": "con", "name": "Mystery.Type" }, + "effects": [] + }, + "params": [], + "body": { "t": "lit", "lit": { "kind": "unit" } } + } + ] +} diff --git a/examples/test_ct1_bare_xmod_rejected.ail.json b/examples/test_ct1_bare_xmod_rejected.ail.json new file mode 100644 index 0000000..ea7b500 --- /dev/null +++ b/examples/test_ct1_bare_xmod_rejected.ail.json @@ -0,0 +1,24 @@ +{ + "schema": "ailang/v0", + "name": "test_ct1_bare_xmod_rejected", + "imports": [], + "defs": [ + { + "kind": "fn", + "name": "main", + "type": { + "k": "fn", + "params": [], + "ret": { "k": "con", "name": "Unit" }, + "effects": ["IO"] + }, + "params": [], + "body": { + "t": "ctor", + "type": "Ordering", + "ctor": "LT", + "args": [] + } + } + ] +} diff --git a/examples/test_ct1_qualified_class_rejected.ail.json b/examples/test_ct1_qualified_class_rejected.ail.json new file mode 100644 index 0000000..929f769 --- /dev/null +++ b/examples/test_ct1_qualified_class_rejected.ail.json @@ -0,0 +1,13 @@ +{ + "schema": "ailang/v0", + "name": "test_ct1_qualified_class_rejected", + "imports": [], + "defs": [ + { + "kind": "instance", + "class": "prelude.Eq", + "type": { "k": "con", "name": "Int" }, + "methods": [] + } + ] +}