From 24af13e7e07005c69088934e4307f72d633b6bbe Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 10 May 2026 21:25:26 +0200 Subject: [PATCH] iter 23.1.3 fixup: cover AmbiguousType branch with cross-module test --- crates/ailang-check/src/lib.rs | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/crates/ailang-check/src/lib.rs b/crates/ailang-check/src/lib.rs index 5990123..2757758 100644 --- a/crates/ailang-check/src/lib.rs +++ b/crates/ailang-check/src/lib.rs @@ -3793,6 +3793,88 @@ mod tests { assert!(diags.is_empty(), "expected green; got {diags:?}"); } + /// Iter 23.1: the new bare-type-name imports-fallback in + /// `Term::Ctor` synth (symmetric to `Pattern::Ctor`'s Iter-15a + /// fallback) must report `ambiguous-type` when two imported + /// modules each declare a type with the same bare name, so that + /// a future fixture importing two prelude-shaped modules cannot + /// silently resolve to one of them. + #[test] + fn cross_module_term_ctor_ambiguous_type_errors() { + // Two different libs, each declaring a type `T` (intentional clash) + // with a single ctor each. + let lib_a = Module { + schema: SCHEMA.into(), + name: "lib_a".into(), + imports: vec![], + defs: vec![Def::Type(TypeDef { + name: "T".into(), + vars: vec![], + ctors: vec![Ctor { name: "MkA".into(), fields: vec![] }], + doc: None, + drop_iterative: false, + })], + }; + let lib_b = Module { + schema: SCHEMA.into(), + name: "lib_b".into(), + imports: vec![], + defs: vec![Def::Type(TypeDef { + name: "T".into(), + vars: vec![], + ctors: vec![Ctor { name: "MkB".into(), fields: vec![] }], + doc: None, + drop_iterative: false, + })], + }; + let consumer = Module { + schema: SCHEMA.into(), + name: "use_both".into(), + imports: vec![ + Import { module: "lib_a".into(), alias: None }, + Import { module: "lib_b".into(), alias: None }, + ], + defs: vec![fn_def( + "f", + Type::Fn { + params: vec![], + ret: Box::new(Type::int()), + effects: vec![], + param_modes: vec![], + ret_mode: ParamMode::Implicit, + }, + vec![], + // Bare type_name `T` — both lib_a and lib_b match. + Term::Match { + scrutinee: Box::new(Term::Ctor { + type_name: "T".into(), + ctor: "MkA".into(), + args: vec![], + }), + arms: vec![Arm { + pat: Pattern::Wild, + body: Term::Lit { lit: Literal::Int { value: 0 } }, + }], + }, + )], + }; + let mut modules = BTreeMap::new(); + modules.insert("lib_a".into(), lib_a); + modules.insert("lib_b".into(), lib_b); + modules.insert("use_both".into(), consumer); + let ws = Workspace { + entry: "use_both".into(), + modules, + root_dir: std::path::PathBuf::from("."), + registry: ailang_core::workspace::Registry::default(), + }; + let diags = check_workspace(&ws); + assert!( + diags.iter().any(|d| d.code == "ambiguous-type"), + "expected ambiguous-type diagnostic; got {diags:?}" + ); + } + /// Iter 23.1: the prelude module is implicitly imported into /// every user module. A user module that pattern-matches on /// `LT` / `EQ` / `GT` without an explicit