iter env-unify.1: extract build_check_env, mono uses it

This commit is contained in:
2026-05-10 02:16:21 +02:00
parent cd08f53315
commit d6870d7a62
2 changed files with 94 additions and 87 deletions
+86
View File
@@ -1085,6 +1085,92 @@ pub fn build_module_globals(
/// - The body-check phase is multi-diagnose: each def is checked
/// independently against the assembled env; a failure is recorded and
/// the next def is attempted.
/// Build the workspace-flat `Env` shared by `check_in_workspace`
/// and `mono::build_workspace_env`. Populates every field whose
/// contents are derivable from `Workspace` alone — no
/// `current_module` overlay applied. Both call sites are thin
/// consumers: each clones this env and applies the per-call
/// overlay (`current_module`, `globals` augmented with module fns,
/// `imports`, `rigid_vars`) at the call site.
///
/// Pre-condition: typecheck has succeeded for the workspace
/// (otherwise `build_module_globals` panics — same caller-contract
/// as the pre-refactor `mono::build_workspace_env`).
pub fn build_check_env(ws: &Workspace) -> Env {
let mut env = Env::default();
builtins::install(&mut env);
// env.types + env.ctor_index — workspace-flat from every
// module's Def::Type. Safe to flatten because `check_workspace`
// has already accepted the workspace, so duplicate names cannot
// occur. Mirrors the per-module loop in the pre-refactor
// `check_in_workspace` (which fail-fast aborted on duplicates,
// unreachable here).
for m in ws.modules.values() {
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());
}
}
}
// env.module_globals + env.class_methods — built from
// `build_module_globals(ws)`. The .fns projection feeds
// `module_globals`; the .class_methods entries are merged
// workspace-wide into `class_methods` (uniqueness enforced
// earlier by `workspace::build_registry`'s
// method-name-collision check).
let mg = build_module_globals(ws)
.expect("build_module_globals: pre-condition (typecheck succeeded) violated");
env.module_globals = mg
.iter()
.map(|(k, v)| (k.clone(), v.fns.clone()))
.collect();
for g in mg.values() {
for (n, e) in &g.class_methods {
env.class_methods.insert(n.clone(), e.clone());
}
}
// env.module_types — per-module ADT index.
env.module_types = build_module_types(ws);
// env.module_imports — per-module alias-or-name -> module-name.
// Per-module because aliases collide across modules; sibling
// shape to `module_globals`.
for m in ws.modules.values() {
let mut import_map: BTreeMap<String, String> = BTreeMap::new();
for imp in &m.imports {
let key = imp.alias.clone().unwrap_or_else(|| imp.module.clone());
import_map.insert(key, imp.module.clone());
}
env.module_imports.insert(m.name.clone(), import_map);
}
// env.class_superclasses — walk every module's Def::Class.
for m in ws.modules.values() {
for d in &m.defs {
if let Def::Class(cd) = d {
if let Some(sc) = &cd.superclass {
env.class_superclasses.insert(cd.name.clone(), sc.class.clone());
}
}
}
}
// env.workspace_registry — clone of ws.registry. Used by
// `check_fn`'s concrete-residual no-instance check.
env.workspace_registry = ws.registry.clone();
env
}
fn check_in_workspace(
m: &Module,
ws: &Workspace,
+8 -87
View File
@@ -355,94 +355,15 @@ pub(crate) fn mono_target_key(t: &MonoTarget) -> (String, String, String) {
)
}
/// Iter 22b.3: build the workspace-wide [`crate::Env`] used by
/// the mono pass to re-run [`crate::synth`] on each fn body.
/// Mirrors `check_in_workspace`'s setup: builtins + workspace
/// registry + per-module globals + class-method table +
/// superclass map. Cross-module type defs and consts are NOT
/// installed here — `synth` for mono only needs to (a) recognise
/// class-method names and (b) unify call-site arg types with
/// declared param types. Module-resident fns are still needed
/// for non-class-method calls inside instance bodies.
/// Iter 22b.3 / 2026-05-10 unify: thin wrapper over
/// [`crate::build_check_env`]. The mono pass needs the same
/// workspace-flat `Env` shape as `check_in_workspace`, so both
/// 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).
pub fn build_workspace_env(ws: &Workspace) -> crate::Env {
// Drift risk: this fn and `crate::check_in_workspace` both
// populate `crate::Env`. If `synth` starts reading a new `Env`
// field, update both paths.
let mut env = crate::Env::default();
crate::builtins::install(&mut env);
env.workspace_registry = ws.registry.clone();
// Per-module globals + class method table + superclass map.
// The construction order matches `check_in_workspace` so the
// env shape is interchangeable. `build_module_globals` may
// surface duplicate-def errors for malformed workspaces; the
// mono pass's pre-condition is that typecheck has already
// succeeded, so a failure here is a caller-contract violation.
let module_globals_index = crate::build_module_globals(ws)
.expect("build_module_globals: pre-condition (typecheck succeeded) violated");
env.module_globals = module_globals_index
.iter()
.map(|(mname, g)| (mname.clone(), g.fns.clone()))
.collect();
env.module_types = crate::build_module_types(ws);
// Iter 22c (sibling of commit 13b36cc): per-module import maps so
// `collect_mono_targets` / `collect_residuals_ordered` can seed
// `env.imports` before re-running `synth`. Mirrors
// `check_in_workspace` (lib.rs:1147-1152). Scoped per-module
// because import aliases collide across modules — same shape as
// `env.module_globals`, unlike the workspace-wide flat tables for
// user ADTs (5c5180f).
for m in ws.modules.values() {
let mut import_map: BTreeMap<String, String> = BTreeMap::new();
for imp in &m.imports {
let key = imp.alias.clone().unwrap_or_else(|| imp.module.clone());
import_map.insert(key, imp.module.clone());
}
env.module_imports.insert(m.name.clone(), import_map);
}
// Workspace-wide class-method table: merge per module's
// ModuleGlobals.class_methods.
for (_mname, g) in &module_globals_index {
for (name, entry) in &g.class_methods {
env.class_methods.insert(name.clone(), entry.clone());
}
}
// Superclass map: walk every module's class defs.
for m in ws.modules.values() {
for d in &m.defs {
if let Def::Class(c) = d {
if let Some(sc) = &c.superclass {
env.class_superclasses.insert(c.name.clone(), sc.class.clone());
}
}
}
}
// Iter 22c: seed `env.types` and `env.ctor_index` from every
// module's `Def::Type` entries. `synth`'s bare-name `Term::Ctor`
// path (and three sibling sites in `lib.rs`) consult these flat
// tables; without them, re-running `synth` on an instance method
// body whose type references a user ADT yields `UnknownType`.
// Workspace-wide flat tables are safe here because `check_workspace`
// has already accepted the workspace, so duplicate names cannot
// occur. Mirrors `check_in_workspace` (lib.rs:1099-1128).
for m in ws.modules.values() {
for d in &m.defs {
if let Def::Type(td) = d {
for c in &td.ctors {
env.ctor_index.insert(
c.name.clone(),
crate::CtorRef {
type_name: td.name.clone(),
},
);
}
env.types.insert(td.name.clone(), td.clone());
}
}
}
env
crate::build_check_env(ws)
}
/// Iter 22b.3: re-run [`crate::synth`] on `f`'s body to recover