Implement loop invariant annotation#95
Draft
coord-e wants to merge 1 commit into
Draft
Conversation
Introduce `thrust_macros::invariant!`, a Prusti-style loop invariant placed inside the loop body, plus `thrust_macros::context` which supplies the surrounding generic/`Self` context that an in-body macro cannot see. Frontend (thrust-macros): - `invariant!(|x: T, ...| pred)` expands to a `#[thrust::formula_fn]` over `Model::Ty` parameters and a marker call referencing it, sharing the static semantics of `requires`/`ensures`. The formula function re-declares the threaded generics (and, in methods, `Self` as a synthetic type parameter) and is instantiated via turbofish, which is what lets the in-body macro support generic- and `Self`-typed variables. - `context` stamps the enclosing impl/trait header onto methods and threads the generic context into each `invariant!`. Without it, a concrete non-generic invariant still works; one naming `Self` is rejected with a clear message. - The marker is `thrust_models::__invariant_marker`. The macro crate is split into `context`, `invariant`, and `spec` modules; the root keeps only the proc-macro entry points and the few shared helpers. Analyzer: - Collect invariant markers, map each to its enclosing loop header, and turn the formula function into that header's precondition by binding each named formula parameter to the matching live basic-block parameter. - Resolving a name to a live local errors when several distinct live locals share it (e.g. shadowing) rather than silently picking one. - The marker terminator is elaborated to a plain goto so it is not type-checked as a real call. https://claude.ai/code/session_01WB28auaD8dSQrckqBwJWBt
c9cf2af to
70d145b
Compare
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.
Summary
Adds Prusti-style loop invariant annotations. An invariant is written inside the loop body and refers to live variables by name:
Frontend (
thrust-macros)invariant!(|x: T, ...| pred)expands into a#[thrust::formula_fn]overModel::Typarameters plus a marker call (thrust_models::__invariant_marker) referencing it, so invariants reuse the exact static semantics ofrequires/ensures. The closure parameters name the live variables the invariant constrains.Selfis re-declared as a synthetic type parameter and instantiated with the realSelfthe same way, so invariants may name generic- andSelf-typed variables.#[thrust_macros::context]supplies that context: it stamps the enclosingimpl/traitheader onto each method (also used by method-levelrequires/ensures) and threads the in-scope generics/Selfinto everyinvariant!. It is general-purpose, not invariant-specific.invariant!also works withoutcontextfor a concrete, non-generic invariant; one that namesSelfwithoutcontextis rejected with a message pointing at the fix.context,invariant, andspecmodules; the crate root keeps only the proc-macro entry points and a few shared helpers.Analyzer
gotoso it is not type-checked as a real call.Notes
Model::Tymust mirror its fields, e.g. a one-field tuple struct models as a one-tuple); a mismatching model trips an existing subtyping panic unrelated to this change.Test plan
Self, and no-contextinvariants.cargo test --test ui(201 passed),cargo clippy --all-targets,cargo fmt --checkall clean.https://claude.ai/code/session_01WB28auaD8dSQrckqBwJWBt