diff --git a/crates/ailang-check/src/mono.rs b/crates/ailang-check/src/mono.rs index 00c21af..4e70349 100644 --- a/crates/ailang-check/src/mono.rs +++ b/crates/ailang-check/src/mono.rs @@ -53,7 +53,7 @@ use ailang_core::ast::{Arm, ClassDef, ConstDef, Def, FnDef as AstFnDef, InstanceDef, Pattern, Term, Type}; use ailang_core::workspace::Workspace; -use crate::Result; +use crate::{CtorRef, Result}; use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; @@ -154,16 +154,24 @@ pub fn monomorphise_workspace(ws: &Workspace) -> Result { let env = build_workspace_env(&ws_owned); // re-build: ws_owned has new defs. let module_names: Vec = ws_owned.modules.keys().cloned().collect(); for mname in &module_names { + // Per-module ctor_index overlay — see + // [`apply_per_module_ctor_index_overlay`] for rationale. + // Mirrors the overlay applied in + // `collect_targets_workspace_wide` so the rewrite-phase + // residual replay produces the same residual list as the + // collection-phase walk (cursor alignment depends on it). + let mut env_mod = env.clone(); + apply_per_module_ctor_index_overlay(&mut env_mod, &ws_owned, mname); let n_defs = ws_owned.modules[mname].defs.len(); for i in 0..n_defs { let ordered: Vec> = { let m = &ws_owned.modules[mname]; let d = &m.defs[i]; match d { - Def::Fn(f) => collect_residuals_ordered(f, mname, &env)?, + Def::Fn(f) => collect_residuals_ordered(f, mname, &env_mod)?, Def::Const(c) => { let pseudo = const_as_pseudo_fn(c); - collect_residuals_ordered(&pseudo, mname, &env)? + collect_residuals_ordered(&pseudo, mname, &env_mod)? } _ => continue, } @@ -216,14 +224,22 @@ fn collect_targets_workspace_wide( ) -> Result> { let mut out: Vec = Vec::new(); for (mname, m) in &ws.modules { + // Per-module ctor_index overlay — see + // [`apply_per_module_ctor_index_overlay`] for rationale. The + // env arriving here is workspace-flat (via `build_check_env`); + // synth's `Pattern::Ctor` resolution requires per-module + // shape to keep the qualified-type-name comparison intact + // for cross-module ctor patterns. + let mut env_mod = env.clone(); + apply_per_module_ctor_index_overlay(&mut env_mod, ws, mname); for d in &m.defs { match d { Def::Fn(f) => { - out.extend(collect_mono_targets(f, mname, env)?); + out.extend(collect_mono_targets(f, mname, &env_mod)?); } Def::Const(c) => { let pseudo = const_as_pseudo_fn(c); - out.extend(collect_mono_targets(&pseudo, mname, env)?); + out.extend(collect_mono_targets(&pseudo, mname, &env_mod)?); } _ => {} } @@ -357,11 +373,63 @@ pub(crate) fn mono_target_key(t: &MonoTarget) -> (String, String, String) { /// share one source of truth. Per-fn entry points /// (`collect_mono_targets`, `collect_residuals_ordered`) clone the env /// and apply per-fn overlay (current_module, globals from -/// module_globals, imports from module_imports, rigid_vars). +/// module_globals, imports from module_imports, rigid_vars) plus the +/// per-module ctor/type overlay +/// (see [`apply_per_module_ctor_index_overlay`]). pub fn build_workspace_env(ws: &Workspace) -> crate::Env { crate::build_check_env(ws) } +/// Iter 22c (sibling of commit 5c5180f for `env.ctor_index`): +/// rebuild `env.types` AND `env.ctor_index` to contain ONLY the +/// types and ctors declared in `module_name`'s `Def::Type`s, +/// mirroring `check_in_workspace`'s per-module overlay at +/// `crates/ailang-check/src/lib.rs:1257-1287`. +/// +/// `build_workspace_env` (via `build_check_env`) leaves both fields +/// workspace-flat. Two synth paths need the per-module shape: +/// +/// * `Pattern::Ctor` resolution (lib.rs:2486-2526) does a +/// local-first `ctor_index` lookup followed by an imports-fallback +/// that produces a *qualified* `resolved_type_name` (`Mod.Type`). +/// With a flat `ctor_index`, a cross-module ctor pattern resolves +/// locally and yields a bare type name, mismatching the qualified +/// scrutinee type and firing `CheckError::PatternTypeMismatch`. +/// * `Term::Ctor` synth (lib.rs:1962-2026) does a local-first +/// `env.types` lookup followed by an imports-fallback that +/// produces a qualified `result_type_name`. With a flat `env.types`, +/// a `Term::Ctor` against a prelude (or imported) type resolves +/// locally and yields a bare scrutinee type — which then mismatches +/// the qualified `Pattern::Ctor` `resolved_type_name` produced by +/// the per-module-cleared `ctor_index`. +/// +/// Both fields must be cleared together so the two synth paths agree +/// on bare-vs-qualified naming. Mirrors the pattern in +/// `check_in_workspace`, which clears and rebuilds both for the +/// same reason. +/// +/// Caller-contract assumption: the workspace has already typechecked, +/// so duplicate type or ctor names within a single module cannot +/// occur (the fail-fast `DuplicateType` / `DuplicateCtor` diagnostics +/// in `check_in_workspace` would have surfaced). +fn apply_per_module_ctor_index_overlay(env: &mut crate::Env, ws: &Workspace, module_name: &str) { + env.types.clear(); + env.ctor_index.clear(); + if let Some(m) = ws.modules.get(module_name) { + for d in &m.defs { + if let Def::Type(td) = d { + for c in &td.ctors { + env.ctor_index.insert( + c.name.clone(), + CtorRef { type_name: td.name.clone() }, + ); + } + env.types.insert(td.name.clone(), td.clone()); + } + } + } +} + /// Iter 22b.3: re-run [`crate::synth`] on `f`'s body to recover /// the per-fn residual class constraints. Filter to fully- /// concrete residuals (the only ones eligible for monomorphisation),