Skip to content

Conversation

@coeff-aij
Copy link
Collaborator

This feature allows users to annotate trait methods with predicates. The Thrust verifies that the concrete implementations of those methods and their associated predicates satisfy the annotations given in trait.

  • Example
    The specification for A::double() is expressed through the annotations on Double::double().
    The method refers to the predicate Double::is_double(), whose concrete implementation is provided by A::is_double().
// A is represented as Tuple<Int> in SMT-LIB2 format.
struct A {
    x: i64,
}

trait Double {
    // Support annotations in trait definitions
    #[thrust::predicate]
    fn is_double(self, doubled: Self) -> bool;

    // This annotations are applied to all implementors of the `Double` trait.
    #[thrust::requires(true)]
    #[thrust::ensures(is_double(*self, ^self))]
    fn double(&mut self);
}

impl Double for A {
    // Write concrete definitions for predicates in `impl` blocks
    #[thrust::predicate]
    fn is_double(self, doubled: Self) -> bool {
        // (tuple_proj<Int>.0 self) is equivalent to self.x
        // self.x * 2 == doubled.x is written as following:
        "(=
            (* (tuple_proj<Int>.0 self) 2)
            (tuple_proj<Int>.0 doubled)
        )"; true
    }

    // Check if this method complies with annotations in
    // trait definition.
    fn double(&mut self) {
        self.x += self.x;
    }
}

Comment on lines 287 to 290
if let Some(trait_item_id) = self.get_trait_item(){
tracing::info!("trait item fonud: {}", self.tcx.item_name(trait_item_id.into()).to_string());
let trait_require_annot = self.extract_require_annot(trait_item_id.into(), &param_resolver);
let trait_ensure_annot = self.extract_ensure_annot(trait_item_id.into(), &result_param_resolver);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We can't create new instance of Analyzer for method definitions in trait because they don't appear in MIR. I have extended the self.extract_*_annot() so that they can analyze any definitions not only the one identified by self.local_def_id. This implementation works, but it could be refactored for a clearer architecture.

Copy link
Owner

Choose a reason for hiding this comment

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

I have extended the self.extract_*_annot() so that they can analyze any definitions not only the one identified by self.local_def_id. This implementation works, but it could be refactored for a clearer architecture.

Cool, could you move these extract_*_annot() functions that take DefId to analyze::Analyzer? I'm putting utilities that need tcx and aren't bound to crates, local defs, or basic blocks into analyze::Analyzer.

@coeff-aij coeff-aij requested a review from coord-e February 1, 2026 14:36
@coeff-aij coeff-aij marked this pull request as ready for review February 1, 2026 14:37
@coeff-aij
Copy link
Collaborator Author

We also need to verify that every predicate implementation defined in a trait is annotated with the #[thrust::predicate] attribute. (But I will postpone the implementation of this check for now.)

coeff-aij and others added 2 commits February 3, 2026 15:29
functions in impl blocks

Update src/analyze/local_def.rs

Co-authored-by: Hiromi Ogawa <me@coord-e.com>
@coeff-aij
Copy link
Collaborator Author

I've addressed your review comments.

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.

2 participants