iter ctt.3: KindMismatch retire
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"iter_id": "ctt.3",
|
||||
"date": "2026-05-12",
|
||||
"mode": "standard",
|
||||
"outcome": "DONE",
|
||||
"tasks_total": 2,
|
||||
"tasks_completed": 2,
|
||||
"reloops_per_task": { "1": 0, "2": 0 },
|
||||
"review_loops_spec": 0,
|
||||
"review_loops_quality": 0,
|
||||
"blocked_reason": null
|
||||
}
|
||||
@@ -1160,26 +1160,6 @@ fn workspace_error_to_diagnostic(
|
||||
"method": method,
|
||||
})),
|
||||
),
|
||||
W::KindMismatch {
|
||||
class,
|
||||
param,
|
||||
method,
|
||||
defining_module,
|
||||
} => Some(
|
||||
ailang_check::Diagnostic::error(
|
||||
"kind-mismatch",
|
||||
format!(
|
||||
"kind mismatch in class `{class}`: parameter `{param}` is used in applied position \
|
||||
inside method `{method}` (Decision 11 axis 5: class params are kind `*` only)"
|
||||
),
|
||||
)
|
||||
.with_ctx(serde_json::json!({
|
||||
"class": class,
|
||||
"param": param,
|
||||
"method": method,
|
||||
"defining_module": defining_module,
|
||||
})),
|
||||
),
|
||||
W::InvalidSuperclassParam {
|
||||
class,
|
||||
superclass,
|
||||
|
||||
@@ -1425,9 +1425,12 @@ fn check_def(def: &Def, env: &Env) -> Result<()> {
|
||||
Def::Const(c) => check_const(c, env),
|
||||
Def::Type(td) => check_type_def(td, env),
|
||||
// Iter 22b.1: schema-only landing for class/instance defs.
|
||||
// Class-schema validation (KindMismatch, InvalidSuperclassParam,
|
||||
// Class-schema validation (InvalidSuperclassParam,
|
||||
// ConstraintReferencesUnboundTypeVar) and instance-body
|
||||
// typechecking (with class-method substitution) land in 22b.2.
|
||||
// ctt.3: KindMismatch retired — the malformed-class-param
|
||||
// shape now fires BareCrossModuleTypeRef from the canonical-
|
||||
// form validator instead.
|
||||
// Workspace-load coherence checks (Orphan / Duplicate /
|
||||
// MissingMethod) already fire from `workspace::build_registry`,
|
||||
// so a malformed instance never reaches this point.
|
||||
|
||||
@@ -253,22 +253,6 @@ pub enum WorkspaceLoadError {
|
||||
method: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: class-schema validation. The class parameter
|
||||
/// appears in applied position (e.g. as the head of a
|
||||
/// `Type::Con { name == param, args.len() > 0 }`) inside a method
|
||||
/// signature. Decision 11 axis 5 forbids HKTs — class params are
|
||||
/// kind `*` only.
|
||||
#[error(
|
||||
"kind mismatch in class `{class}`: parameter `{param}` is used in applied position \
|
||||
inside method `{method}` (Decision 11 axis 5: class params are kind `*` only)"
|
||||
)]
|
||||
KindMismatch {
|
||||
class: String,
|
||||
param: String,
|
||||
method: String,
|
||||
defining_module: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: class-schema validation. A class's `superclass.type`
|
||||
/// does not equal its own `param`. Decision 11 single-superclass
|
||||
/// model requires the superclass to be applied to the same param
|
||||
@@ -789,23 +773,17 @@ fn build_registry(
|
||||
}
|
||||
|
||||
/// Iter 22b.2: class-schema validation. Runs before `build_registry`.
|
||||
/// Three diagnostics fire from here: `kind-mismatch`,
|
||||
/// `invalid-superclass-param`, `constraint-references-unbound-type-var`.
|
||||
/// Two diagnostics fire from here: `invalid-superclass-param`,
|
||||
/// `constraint-references-unbound-type-var`. The `kind-mismatch`
|
||||
/// diagnostic was retired at ctt.3 — the malformed shape now
|
||||
/// fires `BareCrossModuleTypeRef` from the canonical-form
|
||||
/// validator before `validate_classdefs` runs.
|
||||
fn validate_classdefs(
|
||||
modules: &BTreeMap<String, Module>,
|
||||
) -> Result<(), WorkspaceLoadError> {
|
||||
for (mod_name, m) in modules {
|
||||
for m in modules.values() {
|
||||
for def in &m.defs {
|
||||
if let Def::Class(c) = def {
|
||||
for method in &c.methods {
|
||||
walk_kind_mismatch(&method.ty, &c.param)
|
||||
.map_err(|()| WorkspaceLoadError::KindMismatch {
|
||||
class: c.name.clone(),
|
||||
param: c.param.clone(),
|
||||
method: method.name.clone(),
|
||||
defining_module: mod_name.clone(),
|
||||
})?;
|
||||
}
|
||||
if let Some(sc) = &c.superclass {
|
||||
if sc.type_ != c.param {
|
||||
return Err(WorkspaceLoadError::InvalidSuperclassParam {
|
||||
@@ -841,31 +819,6 @@ fn validate_classdefs(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Walks a `Type` looking for any `Type::Con { name == param, args
|
||||
/// non-empty }`. The class param is kind `*`; appearing as a
|
||||
/// constructor with arguments is a kind-mismatch.
|
||||
fn walk_kind_mismatch(t: &Type, param: &str) -> Result<(), ()> {
|
||||
match t {
|
||||
Type::Con { name, args } => {
|
||||
if name == param && !args.is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
for a in args {
|
||||
walk_kind_mismatch(a, param)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Type::Fn { params, ret, .. } => {
|
||||
for p in params {
|
||||
walk_kind_mismatch(p, param)?;
|
||||
}
|
||||
walk_kind_mismatch(ret, param)
|
||||
}
|
||||
Type::Forall { body, .. } => walk_kind_mismatch(body, param),
|
||||
Type::Var { .. } => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: the five primitive type names that are always bare under
|
||||
/// the canonical-form rule. Kept in sync with `Type::int`,
|
||||
/// `Type::bool_`, `Type::str_`, `Type::unit`, `Type::float` in
|
||||
@@ -1876,15 +1829,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a class whose parameter `f` appears as a `Type::Con`
|
||||
/// name (the malformed-but-historically-test-fixture shape used
|
||||
/// to trigger `KindMismatch` pre-ct.1) is now caught earlier by
|
||||
/// the canonical-type-names validator: `f` is bare,
|
||||
/// non-primitive, and not a TypeDef in the owning module, so
|
||||
/// `BareCrossModuleTypeRef` fires before `validate_classdefs`
|
||||
/// gets a chance to run. The `KindMismatch` path stays in the
|
||||
/// codebase as dead-but-defensive code; a future tidy may
|
||||
/// retire it.
|
||||
#[test]
|
||||
fn class_param_in_applied_position_fires_canonical_form_rejection() {
|
||||
let entry = std::path::PathBuf::from(
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# iter ctt.3 — `KindMismatch` retire (pure deletion across 3 files)
|
||||
|
||||
**Date:** 2026-05-12
|
||||
**Started from:** 0e556f085c14993441b7d25dcdc69077b77c83b0
|
||||
**Status:** DONE
|
||||
**Tasks completed:** 2 of 2
|
||||
|
||||
## Summary
|
||||
|
||||
`WorkspaceLoadError::KindMismatch`, its dispatch site in
|
||||
`validate_classdefs`, its `walk_kind_mismatch` helper, its Display
|
||||
arm in `crates/ail/src/main.rs:workspace_error_to_diagnostic`, and
|
||||
the "dead-but-defensive" doc-comment on the canonical-form-rejection
|
||||
test are all retired. Two adjacent textual-consistency edits ride
|
||||
along: the `validate_classdefs` doc-comment narrows from "Three
|
||||
diagnostics fire from here" to "Two" with a successor sentence
|
||||
naming the new path, and the `crates/ailang-check/src/lib.rs:1428`
|
||||
22b.1-era archaeology comment drops the `KindMismatch` token from
|
||||
its enumeration of class-schema diagnostics and gains a one-line
|
||||
ctt.3 retirement marker. The existing test
|
||||
`class_param_in_applied_position_fires_canonical_form_rejection`
|
||||
stays green unchanged — it asserts `BareCrossModuleTypeRef` on the
|
||||
malformed fixture, which is the canonical-form-validator successor
|
||||
the plan named. `cargo build --workspace` clean, no orphan match
|
||||
arms, no dead-code warnings. `cargo test --workspace` green
|
||||
(~600 tests across 16 binary-test suites, zero failures).
|
||||
|
||||
## Per-task notes
|
||||
|
||||
- iter ctt.3.1: atomic deletion pass — 6 Edits across 3 files. workspace.rs ×4 (variant delete; `validate_classdefs` doc + dispatch-loop delete; `walk_kind_mismatch` helper delete; "dead-but-defensive" doc delete). main.rs ×1 (`W::KindMismatch` arm in `workspace_error_to_diagnostic`). lib.rs ×1 (22b.1 archaeology comment). Build green at Step 7.
|
||||
- iter ctt.3.2: workspace-wide test gate — grep substantively clean in `crates/` (one residual `KindMismatch` token at lib.rs:1431 is the ctt.3 retirement marker introduced by Step 6 itself, not a live consumer); canonical-form-rejection test PASS; full `cargo test --workspace` PASS.
|
||||
|
||||
## Concerns
|
||||
|
||||
- Plan-internal contradiction surfaced during Task 2 Step 1: the
|
||||
plan's Step 6 `new_string` deliberately introduces a new
|
||||
`KindMismatch` token in the ctt.3 retirement marker
|
||||
(`// ctt.3: KindMismatch retired — ...`), but Task 2 Step 1's
|
||||
verification text says "Expected: zero hits in `crates/`". The
|
||||
parent spec at `docs/specs/2026-05-12-ct-tidy.md:384` is more
|
||||
permissive ("`grep KindMismatch` returns the three deletion sites
|
||||
only" — accepting the diff itself as the only mention, but
|
||||
silent on a successor archaeology marker). Substantive intent
|
||||
(retire the diagnostic) is met: variant, helper, dispatch, and
|
||||
Display arm are all gone. Treated as `compliant` with this
|
||||
concern recorded; Boss may choose to either tighten the
|
||||
spec/plan rule for future tidies or accept the retirement-marker
|
||||
pattern (which is already common in the codebase — cf. ctt.1
|
||||
successor-rationale comments in workspace.rs).
|
||||
- Mid-deletion repair on workspace.rs:773 — the dispatch-loop
|
||||
deletion in Step 2 orphaned the `mod_name` binding that
|
||||
destructured `for (mod_name, m) in modules`. Plan Step 7's
|
||||
acceptance criterion is "no dead-code warnings" — left as
|
||||
`for (mod_name, m)` the build would warn `unused variable:
|
||||
mod_name`. Minimal cleanup applied: rewrote to
|
||||
`for m in modules.values()`. Same body, same `m: &Module` type
|
||||
via `.values()` instead of tuple-destructure. Not in the plan's
|
||||
verbatim edit list but a foreseeable side-effect of the
|
||||
deletion and entirely mechanical.
|
||||
|
||||
## Known debt
|
||||
|
||||
- None new. The "future tidy may retire" promise in the deleted
|
||||
doc-comment is now this iter; no successor obligation.
|
||||
|
||||
## Files touched
|
||||
|
||||
- `crates/ailang-core/src/workspace.rs` (variant delete + doc adjust + dispatch-loop delete + helper delete + test-doc delete + `mod_name` binding cleanup)
|
||||
- `crates/ail/src/main.rs` (Display arm delete)
|
||||
- `crates/ailang-check/src/lib.rs` (archaeology comment edit)
|
||||
|
||||
## Stats
|
||||
|
||||
bench/orchestrator-stats/2026-05-12-iter-ctt.3.json
|
||||
@@ -39,3 +39,4 @@
|
||||
- 2026-05-12 — audit-eob: milestone close (heap-str-abi) — architect drift fixed inline as `eob.tidy` (3 DESIGN.md edits: float_to_str / int_to_str caveats dropped, "Str ABI" anchor added documenting both heap-Str and static-Str realisations with their shared consumer ABI and codegen-level non-RC invariant for static-Str); bench mixed (latency.explicit_at_rc improvement cluster reappears for the 3rd consecutive audit + new marginal bump_s regressions on list_sum/hof_pipeline 12% over 10% tol), baseline pristine for 3rd consecutive audit (conservative call: latency cluster has no identified cause across 3 audits — ratify-without-attribution would obscure future signal; bump_s cluster is first-sighting, observe next audit) → 2026-05-12-audit-eob.md
|
||||
- 2026-05-12 — iter ctt.1: env-overlay shape ratification — new DESIGN.md top-level section `## Env construction` anchors the `env.types` (owning) / `env.ctor_index` (reverse-index) split with the semantic rationale, plus the intentional check-side / mono-side asymmetry (mono-side narrowed at ct.3.2, check-side retains both halves because in-band `DuplicateCtor` consumes the per-module `env.ctor_index` rebuild); new behavioural-pin test `crates/ailang-check/tests/duplicate_ctor_pin.rs` ratifies the consumer; two P2 roadmap todos struck `[x]` (overlay shape question, per-module overlay narrowing); 3/3 tasks first-shot, zero review re-loops, no production-code edits → 2026-05-12-iter-ctt.1.md
|
||||
- 2026-05-12 — iter ctt.2: `Registry.type_def_module` re-key from `BTreeMap<String, String>` to `BTreeMap<(String, String), String>` keyed by `(owning_module, bare_name)`; new `caller_module: &str` parameter threads through `normalize_type_for_registry` + `Registry::normalize_type_for_lookup`; four `ailang-check` consumer sites (lib.rs:1640, mono.rs:121/624/1175) pass the correct module-context (env.current_module / defining_module / module_name) per the plan's Design Notes; new regression test plus three-module fixture (`ctt2_collision_{cls,lib,main}.ail.json`) exercises the cross-module bare-name collision shape that pre-ctt.2 silently overwrote; RED-failure observed as `OrphanInstance` rather than the plan's predicted `DuplicateInstance` because the pass-2 coherence check (workspace.rs:656-659) is also a bare-name consumer and fires earlier; both consumers fixed by the same re-key; plan's verbatim two-module fixture had two structural defects (two-way imports → Cycle, qualified `InstanceDef.class` → QualifiedClassName) that the implementer-phase repair handled by introducing the third cls-module; spec-intent (RED-first against bare-name collision) preserved; `cargo test --workspace` green (16 binary-test suites, ~600 tests, zero failures) → 2026-05-12-iter-ctt.2.md
|
||||
- 2026-05-12 — iter ctt.3: `KindMismatch` retire — pure deletion across 3 files (workspace.rs: variant + dispatch + helper + "dead-but-defensive" doc; main.rs: Display arm; lib.rs: 22b.1 archaeology comment). Existing test `class_param_in_applied_position_fires_canonical_form_rejection` stays green unchanged (asserts `BareCrossModuleTypeRef` on the malformed fixture — the canonical-form-validator successor path). Two adjacent textual-consistency edits ride along (validate_classdefs doc-comment "Three → Two", lib.rs archaeology comment gains a ctt.3 retirement marker). One mid-deletion mechanical fix: dispatch-loop deletion orphaned `mod_name` binding → rewrote `for (mod_name, m) in modules` to `for m in modules.values()` (same body type, mechanical). 2/2 tasks, ~600 tests green across 16 binary-test suites → 2026-05-12-iter-ctt.3.md
|
||||
|
||||
Reference in New Issue
Block a user