The mono pass re-runs synth on every fn body to recover residual class
constraints. build_workspace_env (delegating to build_check_env) leaves
env.types and env.ctor_index workspace-flat. The synth path for cross-
module Pattern::Ctor / Term::Ctor resolution depends on a per-module
shape — local-first lookup, then imports-fallback that produces a
qualified type name. Without the overlay, the local-flat hit short-
circuits the fallback and yields a bare type name, mismatching the
qualified scrutinee/pattern from the sibling path with
CheckError::PatternTypeMismatch.
Add a per-module overlay helper that clears and rebuilds both
env.types and env.ctor_index from the current module's Def::Type list
— mirroring check_in_workspace at lib.rs:1257-1287 — and apply it at
the two mono entry points that re-walk bodies: the Phase 3 rewrite
loop in monomorphise_workspace and collect_targets_workspace_wide.
Pinned by tests/mono_xmod_ctor_pattern.rs (e580f75); also unblocks
the latent E2E regressions nested_ctor_pattern_first_two_sum,
std_either_list_demo, and ordering_match_via_prelude_prints_1 that
surfaced once the typeclass gate in workspace_has_typeclasses flipped
to true.
This commit is contained in:
@@ -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<Workspace> {
|
||||
let env = build_workspace_env(&ws_owned); // re-build: ws_owned has new defs.
|
||||
let module_names: Vec<String> = 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<Option<MonoTarget>> = {
|
||||
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<Vec<MonoTarget>> {
|
||||
let mut out: Vec<MonoTarget> = 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),
|
||||
|
||||
Reference in New Issue
Block a user