iter ct.2.2-followup: delete dead AmbiguousCtor variant + refresh stale comment + fold redundant re-match
Quality-review follow-up on ct.2.2 (b3c3b60).
- Delete CheckError::AmbiguousCtor: its sole producer (the Pattern::Ctor
imports-fallback) was removed in ct.2.2, leaving the variant, the
code()/ctx() arms, and the diagnostic.rs doc-comment as dead surface.
Workspace grep confirms no remaining Rust consumers. AmbiguousType
stays (it still has a Term::Ctor producer, scheduled for symmetric
removal in ct.2.3).
- Refresh the per-module-overlay rationale comment in check_in_workspace:
it still cited the now-defunct Pattern::Ctor local-first / imports-
fallback path. The overlay's current job is duplicate detection plus
bare-name lookups for local Term::Ctor synth.
- Fold the awkward re-match in type_check_pattern: the first match on
expected now binds scrutinee_args alongside resolved_type_name /
resolved_td / resolved_owning_module, deleting the second match +
unreachable!(). Collapse the any-then-expect ctor lookup into a single
find().ok_or(UnknownCtorInPattern).
Build green, 449+ tests green across the workspace.
This commit is contained in:
@@ -40,7 +40,6 @@
|
||||
//! - `module-name-mismatch` — workspace loader (Iter 5b, in the CLI path)
|
||||
//! - `module-hash-mismatch` — workspace loader (Iter 5b, in the CLI path)
|
||||
//! - `tail-call-not-in-tail-position` (Iter 14e, see Decision 8)
|
||||
//! - `ambiguous-ctor` — `ctx`: `{"ctor": "<n>", "candidates": ["m1.T", "m2.T"]}` (Iter 15a)
|
||||
//! - `use-after-consume` — `ctx`: `{"binder": "<n>"}` (Iter 18c.2);
|
||||
//! carries non-empty [`Diagnostic::suggested_rewrites`] showing how to
|
||||
//! spell the fix in form-A AILang.
|
||||
|
||||
@@ -431,18 +431,6 @@ pub enum CheckError {
|
||||
#[error("call marked `tail` is not in tail position")]
|
||||
TailCallNotInTailPosition,
|
||||
|
||||
/// Iter 15a: a bare `Pattern::Ctor.ctor` did not resolve against the
|
||||
/// current module's `ctor_index` and resolved against ctors in two
|
||||
/// or more imported modules. The author must qualify the scrutinee
|
||||
/// type so that ctor lookup is unambiguous (e.g. write
|
||||
/// `(con std_maybe.Maybe (con Int))` for the scrutinee). Code:
|
||||
/// `ambiguous-ctor`. `ctx`: `{"ctor": "<n>", "candidates": ["m1.T", "m2.T"]}`.
|
||||
#[error("ambiguous constructor `{ctor}`: declared in {candidates:?}")]
|
||||
AmbiguousCtor {
|
||||
ctor: String,
|
||||
candidates: Vec<String>,
|
||||
},
|
||||
|
||||
/// Iter 23.1.3: a bare `Term::Ctor.type_name` did not resolve
|
||||
/// against the current module's local `env.types` and resolved
|
||||
/// against type defs in two or more imported modules. The author
|
||||
@@ -553,7 +541,6 @@ impl CheckError {
|
||||
CheckError::UnknownImport { .. } => "unknown-import",
|
||||
CheckError::InvalidDefName { .. } => "invalid-def-name",
|
||||
CheckError::TailCallNotInTailPosition => "tail-call-not-in-tail-position",
|
||||
CheckError::AmbiguousCtor { .. } => "ambiguous-ctor",
|
||||
CheckError::AmbiguousType { .. } => "ambiguous-type",
|
||||
CheckError::ReuseAsNonAllocatingBody { .. } => "reuse-as-non-allocating-body",
|
||||
CheckError::MissingConstraint { .. } => "missing-constraint",
|
||||
@@ -593,9 +580,6 @@ impl CheckError {
|
||||
CheckError::InvalidDefName { name } => {
|
||||
serde_json::json!({"name": name, "reason": "contains-dot"})
|
||||
}
|
||||
CheckError::AmbiguousCtor { ctor, candidates } => {
|
||||
serde_json::json!({"ctor": ctor, "candidates": candidates})
|
||||
}
|
||||
CheckError::AmbiguousType { type_name, candidates } => {
|
||||
serde_json::json!({"type_name": type_name, "candidates": candidates})
|
||||
}
|
||||
@@ -1248,12 +1232,17 @@ fn check_in_workspace(
|
||||
let mut errors: Vec<CheckError> = Vec::new();
|
||||
|
||||
// Per-module overlay for `env.types` / `env.ctor_index`:
|
||||
// `build_check_env` populates these workspace-flat for the
|
||||
// mono pass, but `check_def` (specifically `Pattern::Ctor`'s
|
||||
// local-first / imports-fallback resolution at the qualified
|
||||
// type-name path) expects only THIS module's local entries.
|
||||
// Clear and rebuild per-module, with the original fail-fast
|
||||
// duplicate diagnostics in-band.
|
||||
// `build_check_env` populates these workspace-flat, but the
|
||||
// per-module pass needs only THIS module's local entries.
|
||||
// Clear and rebuild so that:
|
||||
// - duplicate-type / duplicate-ctor detection (the in-band
|
||||
// errors below) sees only this module's defs;
|
||||
// - bare-name lookups (e.g. local `Term::Ctor` synth)
|
||||
// resolve against this module's types, not against the
|
||||
// workspace-flat union.
|
||||
// Cross-module `Pattern::Ctor` resolution no longer touches
|
||||
// this overlay — that path is type-driven via `expected` and
|
||||
// consults `env.module_types` directly (ct.2.2).
|
||||
env.types.clear();
|
||||
env.ctor_index.clear();
|
||||
for def in &m.defs {
|
||||
@@ -2494,9 +2483,9 @@ fn type_check_pattern(
|
||||
// TypeDef, qualified = explicit cross-module). Derive the
|
||||
// TypeDef from `expected` and find the ctor by name within
|
||||
// it; no env.ctor_index consult, no imports-walk.
|
||||
let (resolved_type_name, resolved_td, resolved_owning_module) =
|
||||
let (resolved_type_name, resolved_td, resolved_owning_module, scrutinee_args) =
|
||||
match expected {
|
||||
Type::Con { name, args: _ } => {
|
||||
Type::Con { name, args } => {
|
||||
if let Some((owner, suffix)) = name.split_once('.') {
|
||||
let td = env
|
||||
.module_types
|
||||
@@ -2509,7 +2498,7 @@ fn type_check_pattern(
|
||||
ty: ailang_core::pretty::type_to_string(expected),
|
||||
}
|
||||
})?;
|
||||
(name.clone(), td, Some(owner.to_string()))
|
||||
(name.clone(), td, Some(owner.to_string()), args.clone())
|
||||
} else {
|
||||
let td = env.types.get(name).cloned().ok_or_else(|| {
|
||||
CheckError::PatternTypeMismatch {
|
||||
@@ -2517,7 +2506,7 @@ fn type_check_pattern(
|
||||
ty: ailang_core::pretty::type_to_string(expected),
|
||||
}
|
||||
})?;
|
||||
(name.clone(), td, None)
|
||||
(name.clone(), td, None, args.clone())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -2527,21 +2516,12 @@ fn type_check_pattern(
|
||||
});
|
||||
}
|
||||
};
|
||||
// Validate the ctor exists in the resolved TypeDef.
|
||||
if !resolved_td.ctors.iter().any(|c| &c.name == ctor) {
|
||||
return Err(CheckError::UnknownCtorInPattern(ctor.clone()));
|
||||
}
|
||||
// expected is already validated as Type::Con above.
|
||||
let scrutinee_args: Vec<Type> = match expected {
|
||||
Type::Con { args, .. } => args.clone(),
|
||||
_ => unreachable!("matched above"),
|
||||
};
|
||||
let td = &resolved_td;
|
||||
let cdef = td
|
||||
.ctors
|
||||
.iter()
|
||||
.find(|c| &c.name == ctor)
|
||||
.expect("indexed ctor exists");
|
||||
.ok_or_else(|| CheckError::UnknownCtorInPattern(ctor.clone()))?;
|
||||
if fields.len() != cdef.fields.len() {
|
||||
return Err(CheckError::CtorArity {
|
||||
ty: resolved_type_name.clone(),
|
||||
|
||||
Reference in New Issue
Block a user