Skip to content

Emit Model predicates for associated types referenced only in specs#134

Merged
coord-e merged 5 commits into
mainfrom
claude/optimistic-johnson-hjxsbb
Jun 16, 2026
Merged

Emit Model predicates for associated types referenced only in specs#134
coord-e merged 5 commits into
mainfrom
claude/optimistic-johnson-hjxsbb

Conversation

@coord-e

@coord-e coord-e commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Problem

model_where_predicates only scanned the method signature (sig.inputs / sig.output) for associated-type projections. A projection like <Self::Item as Model>::Ty that appears only inside a spec/invariant body (e.g. an ensures formula) was never seen, so no Self::Item: Model bound was emitted and the lowered predicate signatures failed to typecheck:

error[E0277]: ``&lt;Self as Iterator&gt;``::Item: thrust_models::Model is not satisfied

Adding both Self::Item: Model and <Self::Item as Model>::Ty: PartialEq (exactly what model_predicates emits per type) clears it.

Fix

Two steps:

  1. Propagate associated item info through #[thrust_macros::context]. FnOuterItem::into_header_only previously cleared all items, dropping the type Item; declarations from the #[thrust::_outer_context(..)] header. It now retains associated type items, and a new associated_type_idents() accessor reads them back.

  2. Attach Model/PartialEq predicates to every associated type in scope. model_where_predicates now enumerates the outer impl/trait's associated types and emits Self::Item: thrust_models::Model + <Self::Item as thrust_models::Model>::Ty: PartialEq for each — whether or not the projection appears in the signature. Results are deduplicated against the signature-scanned projections (same token-string dedup already used in invariant.rs), and they flow correctly through the invariant Self -> __ThrustSelf rewriting path.

Tests

Adds a fail/pass test pair trait_assoc_type_spec (a trait whose ensures references Self::Item only inside the formula body):

  • fail: produces is unsatisfiable (false), so exists(|x| produces(*self, x)) cannot be proven (Unsat).
  • pass: produces is satisfiable (x == self.v), so the exists holds.

Verified locally against the CI-pinned solvers (z3 4.13.0 + the COAR pcsat image): full cargo test --test ui is green (238 passed), and cargo fmt/cargo clippy -D warnings are clean.

https://claude.ai/code/session_01Juzob4ch5BFshNw9RqNtPi


Generated by Claude Code

claude added 2 commits June 16, 2026 16:14
A projection like <Self::Item as Model>::Ty can appear only inside a
spec/invariant body, which is not part of the method signature that
model_where_predicates scanned. As a result no Self::Item: Model bound was
emitted and the lowered predicate signatures failed to typecheck (E0277).

Propagate associated type declarations through #[thrust_macros::context]
(into_header_only now keeps associated type items) and attach the
Model/PartialEq predicates for every associated type in scope of the outer
impl/trait, deduplicating against the signature-scanned projections.
Pairs the trait_assoc_type_spec test by the fail/pass convention: the fail
case has an unsatisfiable predicate (produces is always false) so the
exists postcondition cannot be proven, while the pass case uses a
satisfiable predicate (x == self.v).
coord-e and others added 2 commits June 17, 2026 01:35
After simplifying the closure to `|x|`, `Model` is no longer referenced, so
the import triggered a machine-applicable unused_imports warning. ui_test
switches into rustfix mode for any such warning and then fails trying to read
a missing .fixed golden file.
@coord-e coord-e marked this pull request as ready for review June 16, 2026 16:45
@coord-e coord-e requested a review from Copilot June 16, 2026 16:45

Copilot AI 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

This PR fixes a typechecking gap in thrust-macros where Model/PartialEq bounds were not emitted for associated types referenced only inside spec/invariant bodies (not in method signatures), causing lowered predicate signatures to fail to typecheck.

Changes:

  • Preserve associated type items when embedding the outer impl/trait header via #[thrust::_outer_context(..)], and expose them via associated_type_idents().
  • Extend model_where_predicates to emit T: Model and <T as Model>::Ty: PartialEq bounds for all associated types declared by the outer impl/trait, with deduplication.
  • Add UI pass/fail coverage for a trait whose ensures references Self::Item only inside the formula body.

Reviewed changes

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

File Description
thrust-macros/src/formula_fn_type_lowering.rs Emits model predicates for outer associated types and deduplicates generated where-predicates.
thrust-macros/src/fn_outer_item.rs Retains associated type items in header-only outer context and provides associated_type_idents().
tests/ui/pass/trait_assoc_type_spec.rs Adds a passing UI test ensuring associated types used only in specs get required bounds.
tests/ui/fail/trait_assoc_type_spec.rs Adds a failing UI test validating the expected solver failure mode (Unsat).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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: cd15db92d1

ℹ️ 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 thread thrust-macros/src/formula_fn_type_lowering.rs
A GAT (`type Item<U>;`) requires generic arguments, so fabricating a bare
`Self::Item: Model` bound from it is ill-formed (E0107) and rejects the macro
expansion before verification. Only enumerate associated types without generic
parameters; GATs are left as a TODO.
@coord-e coord-e merged commit cd6b707 into main Jun 16, 2026
6 checks passed
@coord-e coord-e deleted the claude/optimistic-johnson-hjxsbb branch June 16, 2026 16:57
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.

3 participants