The declaration-policy axis: the same Rust, declared differently (#198, step 5) - #408
Merged
Conversation
… step 5, JNI vocabulary) Every cell so far declared each type exactly one way — a struct as a value struct, a handle as a handle. That is a **choice a binding author makes**, separate from the Rust, and while it never varies, whether it decides the answer is invisible. Twelve cases, curated rather than exhaustive: a full product of shape × position × kind would quadruple the matrix to ask a question that is only interesting where a real binding has a real choice. Each row prints the varied answer beside the canonical one, because the difference is the point. Three rows where the policy decides the answer: * `Vec<Rec>` as a **parameter**: crosses when `Rec` is a value struct, and JNI refuses it — by panic — when `Rec` is a handle. Same Rust, same position; the Vec-of-handles rule is about the declaration, and nothing in the value axis could have shown that. * `Option<Rec>` as a C parameter: the canonical run emits Rust that does not compile (the move out of a raw pointer, already a finding), and declaring `Rec` as a handle **avoids it** — so that defect belongs to the by-value path, not to `Option`. * A fieldless enum returned as an opaque handle: refused at compile time by a generated assertion — *"opaque handle types must have alignment >= 2 (bit 0 is the closed tag)"*. `Mode` is byte-aligned, so the tagged-pointer representation cannot hold it. That last one is a **correct refusal**, and it exposed a gap in this report's vocabulary rather than in the generator: a deliberate compile-time rejection and genuinely broken output both land as `bad rust`, since the states come from whether rustc accepted the file and messages are deliberately kept out of the committed report. The legend now says so, and points at #191 — a refusal arriving as a compile error rather than a named rejection at declaration time is exactly that issue's subject. **Scope.** The four kinds varied here are the JNI adapter's own closed vocabulary, which is what makes the axis enumerable at all. C is measured through the same four via the existing translation, so its rows are real but its *coverage* is not: `repr_c_struct`, `opaque_data_struct`, `callback` and the rest have nothing to enumerate against until the C build API is reworked (#192). **Exit: answers move**, additively: 24 new cells, no pre-existing cell changed. Integrity test in the spirit of the others: a policy case must actually vary a declaration. A case whose override matches the canonical kind would print a row duplicating the one beside it — proving nothing while looking like evidence. Part of #198, tracked by #399.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 5 of #198 (the enumerable half), on
shape-coverage(#402).The choice that never varied
Every cell so far declared each type exactly one way — a struct as a value struct, a handle as a handle. But that is a decision a binding author makes, separate from the Rust, and while it never varies, whether it decides the answer is invisible.
Twelve curated cases. Not a product of shape × position × kind, which would quadruple the matrix to ask a question that is only interesting where a real binding has a real choice. Each row prints the varied answer beside the canonical one, because the difference is the point.
Three rows where the policy decides the answer
Vec<Rec>parameter (JNI)rustcpanicOption<Rec>parameter (C)bad rustheaderModereturn (JNI)rustcbad rustVec<Rec>as a parameter crosses whenRecis a value struct and is refused — by panic — whenRecis a handle. Same Rust, same position: the Vec-of-handles rule is about the declaration, and nothing in the value axis could have shown that.Option<Rec>as a C parameter is the reverse. The canonical run emits Rust that does not compile (the move out of a raw pointer, already a finding from step 2), and declaringRecas a handle avoids it — so that defect belongs to the by-value path, not toOption. The axis narrowed an existing finding for free.Modeis byte-aligned, so the tagged-pointer representation cannot hold it.The third one is a finding about this report, not the generator
That refusal is correct — a compile-time guard with a clear message beats undefined behaviour. But it lands as
bad rust, exactly like genuinely broken output, because the state comes from whether rustc accepted the file and messages are deliberately kept out of the committed report (they vary by toolchain).I did not paper over it with an error-code heuristic: basing a state on
E0080would make the report toolchain-sensitive, which is the one property that has kept it identical across 1.85 and stable. Instead the legend now says whatbad rustcovers, and points at #191 — a refusal arriving as a compile error rather than as a named rejection at declaration time is precisely that issue's subject. The run's stderr distinguishes the two.Scope: why this is "the enumerable half"
The four kinds varied here are the JNI adapter's own closed vocabulary, which is what makes the axis enumerable at all. C is measured through the same four by the existing translation, so its rows are real — but its coverage is not:
repr_c_struct,opaque_data_struct,callbackand the rest have nothing to enumerate against until the C build API is reworked (#192). The branch map records that rather than implying the axis is complete.Exit: answers move, additively
24 new cells; no pre-existing cell changed, verified per cell rather than by reading the diff.
Integrity test in the spirit of the others: a policy case must actually vary a declaration. A case whose override matched the canonical kind would print a row duplicating the one beside it — proving nothing while looking like evidence.
Checks
cargo test -p shape-matrix(17 tests), clippy-D warningsover all targets and features,cargo fmt --checkwith CI's config,RUSTDOCFLAGS=-D warnings cargo doc,examples/regen-check.shclean.