//! Pin for `CheckError::DuplicateCtor` — same-named ctors in two //! different ADTs within one module. Ratifies the load-bearing //! consumer of the per-module `env.ctor_index` rebuild in //! `check_in_workspace`. Env construction is code-SoT (the //! `env-construction` ledger row in design/INDEX.md is source-link //! only). The two overlays — typecheck-side rebuild + mono-side //! narrowed — are deliberately asymmetric: the typecheck-side //! `ctor_index` half exists *for this very diagnostic*, while the //! mono-side overlay is narrowed to types-only because the runtime //! ctor lookup is type-driven. If the per-module rebuild is ever //! removed without an equivalent replacement path, this test goes //! red. use ailang_check::check_workspace; use ailang_core::ast::{Ctor, Def, Module, TypeDef}; use ailang_core::workspace::{Registry, Workspace}; use ailang_core::SCHEMA; use std::collections::BTreeMap; #[test] fn duplicate_ctor_across_two_adts_in_one_module() { let m = Module { schema: SCHEMA.into(), name: "M".into(), kernel: false, imports: vec![], defs: vec![ Def::Type(TypeDef { name: "Cat".into(), vars: vec![], ctors: vec![Ctor { name: "Twins".into(), fields: vec![], }], doc: None, drop_iterative: false, param_in: BTreeMap::new(), }), Def::Type(TypeDef { name: "Dog".into(), vars: vec![], ctors: vec![Ctor { name: "Twins".into(), fields: vec![], }], doc: None, drop_iterative: false, param_in: BTreeMap::new(), }), ], }; let mut modules = BTreeMap::new(); modules.insert(m.name.clone(), m.clone()); let ws = Workspace { entry: m.name.clone(), modules, root_dir: std::path::PathBuf::from("."), registry: Registry::default(), }; let diags = check_workspace(&ws); let dup = diags .iter() .find(|d| d.code == "duplicate-ctor") .unwrap_or_else(|| { panic!( "expected at least one `duplicate-ctor` diagnostic, got: {diags:?}" ) }); assert!( dup.message.contains("Twins"), "expected message to name the duplicate ctor `Twins`, got: {}", dup.message ); assert!( dup.message.contains("Cat") && dup.message.contains("Dog"), "expected message to name both ADTs `Cat` and `Dog`, got: {}", dup.message ); }