Skip to content

Fold invariant_context into context - #231

Merged
coord-e merged 1 commit into
mainfrom
claude/unify-context-attribute-8ak4yh
Aug 20, 2026
Merged

Fold invariant_context into context#231
coord-e merged 1 commit into
mainfrom
claude/unify-context-attribute-8ak4yh

Conversation

@coord-e

@coord-ecoord-e commented Aug 16, 2026

Copy link
Copy Markdown
Owner

#[thrust_macros::context] stamped each method of an impl/trait with the enclosing header, while #[thrust_macros::invariant_context] threaded the same header — plus the host signature — into the invariant! calls in a function body. Two attributes for one question: what does the code inside this item see?

They become one. #[thrust_macros::context] now takes a function as well, and an impl/trait hands each of its methods the enclosing header along with the attribute itself, so a method carrying a loop invariant no longer needs one of its own:

#[thrust_macros::context]implCounter{fnrun(&mutself) -> i64{let init = *self;whilerand(){
thrust_macros::invariant!(|init:Self,self:&mutSelf| init.value <= (*self).value);self.value += 1;}
init.value}}

A free function still opts in explicitly, with #[thrust_macros::context] in place of the old name.

Who does what

The impl/trait expansion stays a distributor: it knows which items are methods and what header they sit under, and nothing about what a body holds. It stamps two attributes per method —

#[thrust::_outer_context(implCounter)]#[::thrust_macros::context]fnrun(&mutself) -> i64{ .. }

— and each method's body is then threaded by its own expansion of the attribute, the same one a free function gets, which reads the header back from #[thrust::_outer_context(..)]: the path requires/ensures already take. That expansion accepts a free function, an impl method, or a trait method through the existing FnItemWithSignature, so a trait method with no body needs no special case.

ContextInjector moves over from invariant_context.rs unchanged.

Not extending a where clause nothing asked for

Threading a body that names no invariant! now leaves it alone. invariant_context extended the host's where clause with the Model predicates unconditionally, which was fine while it was opt-in per function; with every method of a #[context] item threaded, those bounds would otherwise land on methods that have no formula to justify them.

Changes

context.rsdispatches on the item: a function is threaded, an impl/trait hands its methods the header and this attribute. ContextInjector moves here from invariant_context.rs, which is deleted
spec.rsFnItemWithSignature::sig_mut, to extend the threaded function's where clause
tests/ui17 files: free functions take #[thrust_macros::context], methods drop the attribute entirely

No behaviour change for the analyzer; the macro expansion each test produces is the same as before.

@coord-e
coord-eforce-pushed the claude/unify-context-attribute-8ak4yh branch from f0652ce to e1aa185CompareAugust 20, 2026 06:33
`#[thrust_macros::context]` stamped each method of an `impl`/`trait` with the
enclosing header, while `#[thrust_macros::invariant_context]` threaded the same
header -- plus the host signature -- into the `invariant!` calls in a function body.
Two attributes for one question: what does the code inside this item see?
They become one. `#[thrust_macros::context]` now takes a function as well, and an
`impl`/`trait` hands each of its methods the enclosing header along with the attribute
itself, so a method carrying a loop invariant no longer needs one of its own:
#[thrust_macros::context]
impl Counter {
fn run(&mut self) -> i64 {
while rand() {
thrust_macros::invariant!(|init: Self, self: &mut Self| ..);
}
}
}
The `impl`/`trait` expansion stays a distributor: it knows which items are methods and
what header they sit under, and nothing about what a body holds. Each method's body is
threaded by its own expansion of the attribute, the same one a free function gets,
which reads the header back from `#[thrust::_outer_context(..)]` -- the path
`requires`/`ensures` already take.
Threading a body that names no spec macro leaves it alone, rather than extending its
where clause with `Model` predicates nothing asked for: with every method of a
`#[context]` item threaded, those bounds would otherwise land on methods that have no
formula to justify them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJ6XNNsSBdPkAzrWHftvqV
@coord-e
coord-eforce-pushed the claude/unify-context-attribute-8ak4yh branch from e1aa185 to 36f8ffeCompareAugust 20, 2026 11:47
@coord-e
coord-e marked this pull request as ready for review August 20, 2026 11:49
@coord-e
coord-e requested a balanced review from CopilotAugust 20, 2026 11:49

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Unifies invariant context propagation under #[thrust_macros::context] for functions, impls, and traits.

Changes:

  • Extends context to rewrite invariants and add required model bounds.
  • Automatically applies context propagation to impl and trait methods.
  • Removes invariant_context and migrates UI tests.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
thrust-macros/src/context.rsImplements unified context expansion.
thrust-macros/src/invariant.rsUpdates context documentation.
thrust-macros/src/invariant_context.rsRemoves superseded implementation.
thrust-macros/src/lib.rsRemoves the old attribute and updates exports.
thrust-macros/src/spec.rsAdds mutable signature access.
tests/ui/pass/loop_invariant_trait.rsTests automatic trait-method context.
tests/ui/pass/loop_invariant_trait_self.rsTests Self invariants in traits.
tests/ui/pass/loop_invariant_self.rsTests automatic impl-method context.
tests/ui/pass/loop_invariant_self_receiver.rsTests receiver-based invariants.
tests/ui/pass/loop_invariant_outer_param.rsMigrates free-function context usage.
tests/ui/pass/loop_invariant_generic.rsMigrates generic invariant coverage.
tests/ui/pass/loop_invariant_generic_closure.rsMigrates generic closure coverage.
tests/ui/pass/loop_invariant_fn_param_closure.rsMigrates closure-parameter coverage.
tests/ui/pass/loop_invariant_fn_param_at_entry.rsMigrates entry-value coverage.
tests/ui/fail/loop_invariant_trait.rsUpdates failing trait invariant test.
tests/ui/fail/loop_invariant_trait_self.rsUpdates failing trait Self test.
tests/ui/fail/loop_invariant_self.rsUpdates failing impl invariant test.
tests/ui/fail/loop_invariant_self_receiver.rsUpdates failing receiver test.
tests/ui/fail/loop_invariant_outer_param.rsUpdates failing outer-parameter test.
tests/ui/fail/loop_invariant_generic.rsUpdates failing generic test.
tests/ui/fail/loop_invariant_fn_param_closure.rsUpdates failing closure test.
tests/ui/fail/loop_invariant_fn_param_at_entry.rsUpdates failing entry-value test.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:36f8ffe231

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadthrust-macros/src/context.rs
Sign up for freeto 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.

3 participants

@coord-e@claude