Capability: a stage the matrix had no word for, and a diagnostic that named the wrong fact #225

Manually merged
dferreira merged 1 commit from feat/225-capability-a-stage-the-matrix-had-no-word-for into master 2026-09-08 17:00:43 +02:00
Owner

Capability: a stage the matrix had no word for, and a diagnostic that named the wrong fact

Along the way:

  • capability: a stage the matrix had no word for, and a diagnostic that named the wrong fact

Touches 13 files: src/rust/crates/ck_cktest/src/capability.rs, src/rust/crates/ck_driver/src/compile/mod.rs, src/rust/crates/ck_driver/src/compile/mono.rs, src/rust/crates/ck_driver/src/user_fns.rs, src/rust/crates/ck_driver/tests/capability.rs, src/rust/crates/ck_types/src/diag.rs and 7 more.

Capability: a stage the matrix had no word for, and a diagnostic that named the wrong fact Along the way: - capability: a stage the matrix had no word for, and a diagnostic that named the wrong fact Touches 13 files: `src/rust/crates/ck_cktest/src/capability.rs`, `src/rust/crates/ck_driver/src/compile/mod.rs`, `src/rust/crates/ck_driver/src/compile/mono.rs`, `src/rust/crates/ck_driver/src/user_fns.rs`, `src/rust/crates/ck_driver/tests/capability.rs`, `src/rust/crates/ck_types/src/diag.rs` and 7 more.
dferreira requested changes 2026-09-08 16:26:35 +02:00
Dismissed
dferreira left a comment

Mostly there, but the question on src/rust/crates/ck_cktest/src/capability.rs needs an answer before this lands.

Mostly there, but the question on `src/rust/crates/ck_cktest/src/capability.rs` needs an answer before this lands.
@ -537,0 +571,4 @@
/// `lower:` and `codegen:` — the place LC6 stamping actually runs.
#[test]
fn monomorphize_is_a_peer_of_the_other_failure_forms() {
let cell = parse_capability("monomorphize: NoInstantiation\n", 1).unwrap();
Owner

cell unwraps here. If this is reachable from user input it is a panic in front of a person rather than an error they can read. Is it provably there at this point, or should it carry a ??

`cell` unwraps here. If this is reachable from user input it is a panic in front of a person rather than an error they can read. Is it provably there at this point, or should it carry a `?`?
@ -135,0 +184,4 @@
variants
.iter()
.map(|v| format!("`{v}`"))
.collect::<Vec<_>>()
Owner

collect allocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?

`collect` allocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?
@ -524,3 +578,3 @@
#[test]
fn concrete_tag_in_a_value_slot_is_not_e0742() {
fn concrete_tag_in_a_value_slot_is_accepted() {
Owner

concrete_tag_in_a_value_slot_is_accepted reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?

`concrete_tag_in_a_value_slot_is_accepted` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
Author
Owner

It is reachable. The function in src/rust/crates/ck_cktest/src/capability.rs returns a Result now and the caller reports it, so the unwrap on cell is gone.

It is reachable. The function in `src/rust/crates/ck_cktest/src/capability.rs` returns a Result now and the caller reports it, so the unwrap on `cell` is gone.
Author
Owner

Split. The decision in concrete_tag_in_a_value_slot_is_accepted is a pure function now, with its own tests in src/rust/crates/ck_types/src/param_args.rs.

Split. The decision in `concrete_tag_in_a_value_slot_is_accepted` is a pure function now, with its own tests in `src/rust/crates/ck_types/src/param_args.rs`.
Author
Owner

It runs per token. The buffer behind collect lives on the struct in src/rust/crates/ck_types/src/diag/values.rs now and is cleared rather than reallocated.

It runs per token. The buffer behind `collect` lives on the struct in `src/rust/crates/ck_types/src/diag/values.rs` now and is cleared rather than reallocated.
Author
Owner

Pushed a fix for both. The second pass on src/rust/crates/ck_cktest/src/capability.rs is much smaller than the first.

Pushed a fix for both. The second pass on `src/rust/crates/ck_cktest/src/capability.rs` is much smaller than the first.
dferreira approved these changes 2026-09-08 16:55:28 +02:00
dferreira left a comment

That is it for src/rust/crates/ck_cktest/src/capability.rs. Thanks for the second pass.

That is it for `src/rust/crates/ck_cktest/src/capability.rs`. Thanks for the second pass.
Three cells the gate flagged on the merged tree, reconciled against what the
compiler measurably does — and one prose claim deleted because it was false.

WHAT MOVED THEM. Not this tree's slices. `ckc` was rebuilt at every commit from
`b5668540` forward and the three programs re-run at each: the type-cascade
reorder (`fa9b793c`), the newtype rep-type fix (`e514762c`) and the literal
scan-window fix (`3b913301`) leave all three exactly where they already were.
The one commit that moved all three is `2237a6a4`, the size-binder slice, which
is already on `wip_v2`. They surfaced now because `--test capability` is the only
harness that executes these cells and had not run since — the same gap that
stranded the six newtype cells the previous ratchet note records.

1. `const_generic_fn_call`: typecheck: E0760 -> codegen: Unsupported. The E0760
   was never true of the entry the matrix observes. E0760 is the FOOTPRINT DOOR,
   and the door has exactly one call site — `closure_check_diagnostics`
   (`ck_driver/src/load.rs:403`), the `ckc check` projection. The matrix observes
   `ckc run`, whose front-end gate is `render_closure_diagnostics`
   (`ck_driver/src/compile/mod.rs:267`) and does not include the door. The
   declaration was read off the wrong command in the same commit that moved the
   cell.

2. `impl_method_signature_size_param`: codegen: Unsupported ->
   monomorphize: NoInstantiation. LC6 stamping is a real pipeline stage — it runs
   in the DRIVER, after F1 lowered the entry body and before F2 sees anything —
   and `Capability` had no form for it, which the harness said in its own words
   rather than guessing. It gets the sixth form, as a peer and not a carve-out:
   `Stage::Monomorphize` orders strictly between `Lower` and `Codegen` where the
   pass actually runs; `Capability::Monomorphize(String)` carries a variant name
   like `Lower`/`Codegen`; `parse_outcome` routes `monomorphize:` through the
   SAME `parse_variant` its two siblings use; rendering, round-tripping,
   `entry:`-orthogonality and strict two-way reconciliation are the shared code
   paths, exercised by the same unit tests extended one row.

   That form needs a variant to name, so `CompileError::Monomorphize` stops
   carrying a rendered `String` and carries `MonoError` — an enum with four
   variants, `kind()` and `Display`, exactly the shape `ck_lower::LowerError`
   already has and for exactly its reason: the matrix pins a cell to the VARIANT,
   never to a slice of prose, so rewording a message must not move a cell.

3. `money_unknown_currency_tag_is_accepted` -> `money_unknown_currency_tag_refuses`
   (renamed; the old name is now a false claim). runs: 42 -> typecheck: E0757.
   The bug it pinned is FIXED: `Types.ck`:335 says the closed tag exists
   precisely so `Money<ZZZ>` is a compile error, and it is one. `Money<USD>`
   still compiles clean, and so does a name an enclosing `impl` head binds
   (`impl Show2<Money<c>>`) — both measured. So the cell is WORKS and
   BROKEN_CELL_COUNT ratchets 47 -> 46.

E0742 RULING: the tag slot renames. The refusal arrived as E0742, whose text
reads "takes a number the compiler has — a literal, a module `const` that folds,
arithmetic over them, or a size binder an enclosing `<…>` declares". Every clause
of that is false of `Money<currency: Currency>`: the slot takes no number, `USD`
is legal there and is no more a number than `ZZZ` is, and a size binder is not
admissible at all. Broadening E0742 to cover both was the alternative and it
fails Law 2 from the other side: the numeric slot's admissible set (a number) and
the tag slot's (a variant of a closed `data` sum) are DISJOINT, so one code could
only cover both by saying two different things depending on which declaration it
landed on — a diagnostic carrying two facts, exactly what Law 2 forbids. Law 2's
remedy is the one it always is: the new thing renames. E0742 keeps the numeric
slot with its wording untouched; E0757 is the closed-`data`-tag slot and names
the tag plus its full variant set, because a CLOSED set named in full is the
whole answer rather than a hint. It also names the bound-binder spelling, which
is admitted here too — under-covering the admissible set would send the reader to
fix the wrong thing (Law 4). `param_args::closed_tag_slot` picks between the two
off the DECLARED ascription, reading the same `(name, declared type)` pair
`lift::value_slot_tag` reads, so the code that fires and the recogniser that did
not match cannot disagree about what the slot is. No corpus app, stdlib unit or
fixture emits E0742 in a tag slot, so nothing else moves.

THE LOOSE THREAD: the shared root cause was never real, and the claim is deleted
(Law 3), not carried. The money cell said "same root cause as
`let_annotation_names_an_undeclared_type` (type positions are not name-resolved)
… both should go green on the same fix; if only one does, the fix was
incomplete." Measured: they are not the same pass and did not move together.
This refusal is the value-parameter ARGUMENT-FORM check asking whether an
argument fills the slot a head's `GenericParamDecl` declares — it never resolves
`ZZZ` as a type and does not need to. `let x: Nope = 1` is a name in a TYPE slot,
which has no `GenericParamDecl`; at HEAD that program still compiles, links and
runs. `2237a6a4` moved one and left the other exactly where it stood. Type
positions are still not name-resolved.

While correcting it, a second false claim in that cell fell out: it said the
program "checks clean and runs", and `ckc check` now refuses it with E0760 (the
footprint door cannot bound a type nothing resolved). `runs: 42` is still exactly
right for the entry the cell is observed through; the prose was not. Both cells
now record that `ckc check` and `ckc run` DISAGREE on these programs — an
unpinned defect, because `entry:` admits `run` and `test` and neither is `check`.
It is named as a pointer, explicitly not as evidence.

RATCHETS: BROKEN_CELL_COUNT 47 -> 46, justified in place. CELL_COUNT holds at 440
(a rename is not an add). UNMARKED_CELL_COUNT holds at 146:
`impl_method_signature_size_param` is a genuine unmarked BROKEN and marking it
here would have masked the decrement above, so it is left for its own commit.

Gates: `cargo fmt --all --check` 0 diffs; `cargo clippy --workspace --all-targets
-- -D warnings` 0 warnings 0 errors; `cargo test -p ck_cktest --lib` 44/44,
`cargo test -p ck_types --lib` 271/271. The capability gate itself is the main
session's to run.
dferreira manually merged commit 4240fee6d2 into master 2026-09-08 17:00:43 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!225
No description provided.