Skip to content

The call axis: shapes that only exist between parameters (#198, step 4) - #407

Merged
milyin merged 2 commits into
shape-coveragefrom
shape-matrix-calls
Aug 13, 2026
Merged

The call axis: shapes that only exist between parameters (#198, step 4)#407
milyin merged 2 commits into
shape-coveragefrom
shape-matrix-calls

Conversation

@milyin

@milyin milyin commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Step 4 of #198, on shape-coverage (#402).

The axis a per-value cell cannot express

Every cell so far described one value in one position. Aliasing cannot be described that way: two parameters can name the same underlying resource, and what a binding must do about it is a property of the call.

Both generators already say so in their own code. Each emits an alias preflight under a rule about the whole parameter set — at least one consumed handle, and any other handle — and both docs note that the narrower reading ("two consumed parameters") misses the mixed cases, where a borrow dangles the moment a consume takes ownership.

So calls are a second kind of cell, running through the same driver, compile check, header stage and ratchet. Eight, chosen around that rule rather than at random:

Call Why it is here
(Handle, Handle) the case both generators name: one allocation, two consuming converters
(Handle, &Handle) a mixed pair — the narrower rule misses it
(&Handle, &Handle) must not be guarded: two &T to one resource is legal Rust and legal C
(Handle, Option<Handle>) same domain, different spelling — why comparison is on the resource, not the declared type
(Handle, Rec), (Handle, Sum) different domains; nothing to alias
(Rec, Rec) the control — no handles at all
(&Handle, &Handle, Handle) three parameters, consume last: position within a call must not matter

All eight are expressible in both targets — header for C, rustc for JNI. No findings. The value is that a call shape becoming inexpressible now falls below a floor, and that the fixtures exist and are named for the stage that can run them.

What no cell here claims

Whether the guard fires — rejecting the aliased call, sparing the unaliased one, running before ownership moves — is a claim about running code.

I deliberately did not assert it against emitted text. A grep for a guard establishes that the text contains a guard, which is not the property anyone cares about, and this crate has been careful to report only what something mechanical established. Those three discriminations wait for the runtime stage, and the branch map now records them as its debt rather than as a checkbox this step ticked.

Exit: answers move, additively

16 new cells (8 header, 8 rustc). No existing cell changed — verified by diffing the old report against the new one per cell, not by reading the diff.

Two integrity tests

In the spirit of the ones already here:

  • every call parameter is a type the model accepts — otherwise a header cell would be measuring a fixture that never contained the shape it names;
  • every cell id is unique. An id is a file name, a receipt key and a guarantee key at once, so a collision would silently merge two cells: one reporting the other's compiler diagnostics and inheriting the other's floor.

Checks

cargo test -p shape-matrix (16 tests), clippy -D warnings across all targets and features, cargo fmt --check with CI's config, RUSTDOCFLAGS=-D warnings cargo doc, and examples/regen-check.sh clean.

milyin added 2 commits August 14, 2026 01:06
Every cell so far described one value in one position. Aliasing cannot be
described that way: two parameters can name the same underlying resource, and
what a binding must do about it is a property of the **call**. Both generators
already say so in their own code — each emits an alias preflight under a rule
about the whole parameter set (at least one consumed handle, and any other
handle), and both docs note that the narrower reading, "two consumed
parameters", misses the mixed cases.

So calls are a second kind of cell, running through the same driver, the same
compile check, the same header stage and the same ratchet. Eight of them, chosen
around that rule rather than at random: pairs that must be guarded
(consume/consume, consume/borrow, consume/optional), a pair that must **not** be
(borrow/borrow — two `&T` to one resource is legal Rust and legal C, and a guard
there would remove working surface), pairs in different resource domains where
the question does not arise, and one three-parameter call with the consume last,
since position within a call must not matter.

All eight are expressible in both targets: `header` for C, `rustc` for JNI. No
findings — the value is that a call shape becoming inexpressible now falls below
a floor, and that the fixtures exist and are named for the stage that can run
them.

**What no cell here claims.** Whether the guard *fires* — rejecting the aliased
call, sparing the unaliased one, running before ownership moves — is a claim
about running code. It is not asserted against emitted text: a grep for a guard
establishes that the text contains a guard, which is not the property anyone
cares about, and this crate has been careful to report only what something
mechanical established. Those three discriminations wait for the runtime stage.

**Exit: answers move**, additively only: 16 new cells, 8 `header` and 8 `rustc`.
No existing cell changed.

Two integrity tests, in the spirit of the ones already here: every call parameter
is a type the model accepts (or the call measures a fixture that never contained
the shape it names), and every cell id is unique — an id is a file name, a
receipt key and a guarantee key at once, so a collision would silently merge two
cells, one reporting the other's diagnostics and inheriting the other's floor.

Part of #198, tracked by #399.
@milyin
milyin merged commit cdae051 into shape-coverage Aug 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant