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-name-mismatch` — workspace loader (Iter 5b, in the CLI path)
|
||||||
//! - `module-hash-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)
|
//! - `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);
|
//! - `use-after-consume` — `ctx`: `{"binder": "<n>"}` (Iter 18c.2);
|
||||||
//! carries non-empty [`Diagnostic::suggested_rewrites`] showing how to
|
//! carries non-empty [`Diagnostic::suggested_rewrites`] showing how to
|
||||||
//! spell the fix in form-A AILang.
|
//! spell the fix in form-A AILang.
|
||||||
|
|||||||
@@ -431,18 +431,6 @@ pub enum CheckError {
|
|||||||
#[error("call marked `tail` is not in tail position")]
|
#[error("call marked `tail` is not in tail position")]
|
||||||
TailCallNotInTailPosition,
|
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
|
/// Iter 23.1.3: a bare `Term::Ctor.type_name` did not resolve
|
||||||
/// against the current module's local `env.types` and resolved
|
/// against the current module's local `env.types` and resolved
|
||||||
/// against type defs in two or more imported modules. The author
|
/// against type defs in two or more imported modules. The author
|
||||||
@@ -553,7 +541,6 @@ impl CheckError {
|
|||||||
CheckError::UnknownImport { .. } => "unknown-import",
|
CheckError::UnknownImport { .. } => "unknown-import",
|
||||||
CheckError::InvalidDefName { .. } => "invalid-def-name",
|
CheckError::InvalidDefName { .. } => "invalid-def-name",
|
||||||
CheckError::TailCallNotInTailPosition => "tail-call-not-in-tail-position",
|
CheckError::TailCallNotInTailPosition => "tail-call-not-in-tail-position",
|
||||||
CheckError::AmbiguousCtor { .. } => "ambiguous-ctor",
|
|
||||||
CheckError::AmbiguousType { .. } => "ambiguous-type",
|
CheckError::AmbiguousType { .. } => "ambiguous-type",
|
||||||
CheckError::ReuseAsNonAllocatingBody { .. } => "reuse-as-non-allocating-body",
|
CheckError::ReuseAsNonAllocatingBody { .. } => "reuse-as-non-allocating-body",
|
||||||
CheckError::MissingConstraint { .. } => "missing-constraint",
|
CheckError::MissingConstraint { .. } => "missing-constraint",
|
||||||
@@ -593,9 +580,6 @@ impl CheckError {
|
|||||||
CheckError::InvalidDefName { name } => {
|
CheckError::InvalidDefName { name } => {
|
||||||
serde_json::json!({"name": name, "reason": "contains-dot"})
|
serde_json::json!({"name": name, "reason": "contains-dot"})
|
||||||
}
|
}
|
||||||
CheckError::AmbiguousCtor { ctor, candidates } => {
|
|
||||||
serde_json::json!({"ctor": ctor, "candidates": candidates})
|
|
||||||
}
|
|
||||||
CheckError::AmbiguousType { type_name, candidates } => {
|
CheckError::AmbiguousType { type_name, candidates } => {
|
||||||
serde_json::json!({"type_name": type_name, "candidates": 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();
|
let mut errors: Vec<CheckError> = Vec::new();
|
||||||
|
|
||||||
// Per-module overlay for `env.types` / `env.ctor_index`:
|
// Per-module overlay for `env.types` / `env.ctor_index`:
|
||||||
// `build_check_env` populates these workspace-flat for the
|
// `build_check_env` populates these workspace-flat, but the
|
||||||
// mono pass, but `check_def` (specifically `Pattern::Ctor`'s
|
// per-module pass needs only THIS module's local entries.
|
||||||
// local-first / imports-fallback resolution at the qualified
|
// Clear and rebuild so that:
|
||||||
// type-name path) expects only THIS module's local entries.
|
// - duplicate-type / duplicate-ctor detection (the in-band
|
||||||
// Clear and rebuild per-module, with the original fail-fast
|
// errors below) sees only this module's defs;
|
||||||
// duplicate diagnostics in-band.
|
// - 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.types.clear();
|
||||||
env.ctor_index.clear();
|
env.ctor_index.clear();
|
||||||
for def in &m.defs {
|
for def in &m.defs {
|
||||||
@@ -2494,9 +2483,9 @@ fn type_check_pattern(
|
|||||||
// TypeDef, qualified = explicit cross-module). Derive the
|
// TypeDef, qualified = explicit cross-module). Derive the
|
||||||
// TypeDef from `expected` and find the ctor by name within
|
// TypeDef from `expected` and find the ctor by name within
|
||||||
// it; no env.ctor_index consult, no imports-walk.
|
// 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 {
|
match expected {
|
||||||
Type::Con { name, args: _ } => {
|
Type::Con { name, args } => {
|
||||||
if let Some((owner, suffix)) = name.split_once('.') {
|
if let Some((owner, suffix)) = name.split_once('.') {
|
||||||
let td = env
|
let td = env
|
||||||
.module_types
|
.module_types
|
||||||
@@ -2509,7 +2498,7 @@ fn type_check_pattern(
|
|||||||
ty: ailang_core::pretty::type_to_string(expected),
|
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 {
|
} else {
|
||||||
let td = env.types.get(name).cloned().ok_or_else(|| {
|
let td = env.types.get(name).cloned().ok_or_else(|| {
|
||||||
CheckError::PatternTypeMismatch {
|
CheckError::PatternTypeMismatch {
|
||||||
@@ -2517,7 +2506,7 @@ fn type_check_pattern(
|
|||||||
ty: ailang_core::pretty::type_to_string(expected),
|
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 td = &resolved_td;
|
||||||
let cdef = td
|
let cdef = td
|
||||||
.ctors
|
.ctors
|
||||||
.iter()
|
.iter()
|
||||||
.find(|c| &c.name == ctor)
|
.find(|c| &c.name == ctor)
|
||||||
.expect("indexed ctor exists");
|
.ok_or_else(|| CheckError::UnknownCtorInPattern(ctor.clone()))?;
|
||||||
if fields.len() != cdef.fields.len() {
|
if fields.len() != cdef.fields.len() {
|
||||||
return Err(CheckError::CtorArity {
|
return Err(CheckError::CtorArity {
|
||||||
ty: resolved_type_name.clone(),
|
ty: resolved_type_name.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user