From a8a58cc41e789ff89021bcbe2aabf220b1bd9f49 Mon Sep 17 00:00:00 2001 From: Brummel Date: Mon, 11 May 2026 09:31:48 +0200 Subject: [PATCH] iter ct.3.1: codegen lookup_ctor_by_type direct lookup; delete imports-fallback --- crates/ailang-codegen/src/lib.rs | 95 ++++++++++++-------------------- 1 file changed, 35 insertions(+), 60 deletions(-) diff --git a/crates/ailang-codegen/src/lib.rs b/crates/ailang-codegen/src/lib.rs index 7826631..248d42e 100644 --- a/crates/ailang-codegen/src/lib.rs +++ b/crates/ailang-codegen/src/lib.rs @@ -376,15 +376,15 @@ fn lower_workspace_inner(ws: &Workspace, alloc: AllocStrategy) -> Result let key = imp.alias.clone().unwrap_or_else(|| imp.module.clone()); import_map.insert(key, imp.module.clone()); } - // Iter 23.2 (fourth lockstep site, after Pattern::Ctor 15a / - // Term::Ctor typecheck / lookup_ctor_by_type codegen): mirror - // the typechecker's implicit-prelude import injection - // (crates/ailang-check/src/lib.rs:1198 and :1300). User - // modules that call prelude-resident fns synthesised by Iter - // 22b.3 monomorphisation (e.g. `prelude.eq__Int` from a user - // calling `eq x y` on Ints) need the codegen-side import_map - // to resolve the `prelude.` prefix at the call site - // (`lower_call`'s prefix lookup). + // Iter 23.2: mirror the typechecker's implicit-prelude import + // injection (crates/ailang-check/src/lib.rs:1198 and :1300). + // User modules that call prelude-resident fns synthesised by + // Iter 22b.3 monomorphisation (e.g. `prelude.eq__Int` from a + // user calling `eq x y` on Ints) need the codegen-side + // import_map to resolve the `prelude.` prefix at the call + // site (`lower_call`'s prefix lookup). Post-ct.3 ctor lookup + // is canonical (bare = local, qualified routes via import_map); + // this entry serves fn-name resolution only. if m.name != "prelude" { import_map .entry("prelude".to_string()) @@ -1676,25 +1676,13 @@ impl<'a> Emitter<'a> { } } - /// Iter 15a: resolves a ctor reference by `type_name` (which may be - /// qualified `module.T` or bare `T`) plus a bare ctor name. Returns - /// the same `CtorRef` shape used by the local `ctor_index`. The - /// returned `CtorRef.type_name` is always the bare type name as - /// declared in the owning module. The current `module_name` is the - /// authority for "bare" — that lets a specialised fn body emitted - /// under a swapped `module_name` (see `emit_specialised_fn`) - /// resolve its bare ctor references against the *owner* module's - /// ctor table, not the consumer's. - /// - /// Iter 23.1: bare-type lookup now falls back to imported modules - /// when the ctor is not local — mirroring `lookup_ctor_in_pattern`. - /// The typechecker (Iter 23.1 Task 3) already accepts a bare - /// `Term::Ctor { type_name, ctor }` whose `type_name` is owned by - /// an imported module (the implicit `prelude` import is the - /// motivating case: an `Ordering` ctor `LT` written without an - /// explicit `imports: ["prelude"]`). Codegen must honour the same - /// resolution path so the lockstep `Pattern::Ctor ↔ Term::Ctor ↔ - /// codegen` is preserved. + /// Resolves a `Term::Ctor.type_name` (canonical post-ct.1: bare + /// = local TypeDef, qualified `.` = explicit + /// cross-module) to the codegen-side `CtorRef`. Qualified names + /// route through `import_map`; bare names hit the current + /// module's `module_ctor_index` directly. No imports-walk + /// fallback — the typechecker (post-ct.2) and the workspace + /// validator (post-ct.1) have already pinned canonical form. pub(crate) fn lookup_ctor_by_type( &self, type_name: &str, @@ -1725,43 +1713,30 @@ impl<'a> Emitter<'a> { } Ok(cref) } else { - // Local-first: current module's ctor table wins on a - // type-matching hit. A local ctor with the same name but - // a DIFFERENT `type_name` is not a conflict — typecheck - // has already pinned which type is meant, so the lookup - // falls through to the imports-fallback. Only an - // exhausted scan yields `Err`. - if let Some(cref) = self + // ct.3 Task 1: bare type_name is canonical (post-ct.1 + // validator) ⇒ local. Hit the current module's ctor + // table directly; non-match is a hard error. No + // imports-walk — the typechecker has already pinned + // type_name to the owning module. + let cref = self .module_ctor_index .get(self.module_name) .and_then(|m| m.get(ctor_name)) .cloned() - { - if cref.type_name == type_name { - return Ok(cref); - } - // type_name mismatch — keep looking in imports. + .ok_or_else(|| { + CodegenError::Internal(format!( + "unknown ctor `{ctor_name}` for type `{type_name}` in module `{}`", + self.module_name + )) + })?; + if cref.type_name != type_name { + return Err(CodegenError::Internal(format!( + "ctor `{ctor_name}` belongs to local type `{}`, not `{type_name}`; \ + cross-module ctor refs require qualified type_name", + cref.type_name + ))); } - // Iter 23.1: fallback — scan other modules for a bare ctor - // whose declared `type_name` matches. The typechecker has - // already pinned uniqueness (an ambiguous bare type name - // is rejected with `CheckError::AmbiguousType`), so the - // first hit whose owning type matches the requested - // `type_name` is unique. Mirrors `lookup_ctor_in_pattern`. - for (mname, ctors) in self.module_ctor_index.iter() { - if mname == self.module_name { - continue; - } - if let Some(cref) = ctors.get(ctor_name).cloned() { - if cref.type_name == type_name { - return Ok(cref); - } - } - } - Err(CodegenError::Internal(format!( - "unknown ctor `{ctor_name}` for type `{type_name}` in module `{}`", - self.module_name - ))) + Ok(cref) } }