Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encode trait bounds in AIR/SMT to enable broadcast_forall with trait bounds #747

Closed
wants to merge 9 commits into from

Conversation

Chris-Hawblitzel
Copy link
Collaborator

Up to now, broadcast_forall was only allowed for proof functions with no trait bounds. This pull request adds AIR/SMT encodings of trait bounds so that we generate axioms for broadcast_forall that can include trait bounds as preconditions. This is also relevant to #744 , since axioms about spec function ensures may need preconditions for trait bounds.

Here is an example test:

trait T1<A, B> {}
trait T2<C, D> {}

struct S<E>(E);

impl<X> T1<X, bool> for S<X> {}
impl<Y, Z: T1<int, Y>> T2<Z, u16> for S<(Y, u8)> {}

spec fn f<A>(i: int) -> bool;

#[verifier::external_body]
#[verifier::broadcast_forall]
proof fn p<A: T2<S<int>, u16>>(i: int)
    ensures f::<A>(i)
{
}

proof fn test1() {
    assert(f::<S<(bool, u8)>>(3));
}

proof fn test2() {
    assert(f::<S<(u32, u8)>>(3)); // FAILS
}

proof fn test3() {
    assert(f::<S<(bool, u32)>>(3)); // FAILS
}

In this, only test1 succeeds, because p's trait bound A: T2<S<int>, u16> is satisfied by A = S<(bool, u8)> but not by A = S<(u32, u8)> or A = S<(bool, u32)>. For Z3 to see that the trait bound is satisfied, we need to encode the trait bounds as AIR/SMT predicates. This encoding looks like the following, where each relevant trait impl becomes an axiom:

(declare-fun tr_bound%!T1. (Dcr Type Dcr Type Dcr Type) Bool)
(declare-fun tr_bound%!T2. (Dcr Type Dcr Type Dcr Type) Bool)
(axiom (forall ((X&. Dcr) (X& Type)) (!
   (tr_bound%!T1. $ (TYPE%!S. X&. X&) X&. X& $ BOOL)
   :pattern ((tr_bound%!T1. $ (TYPE%!S. X&. X&) X&. X& $ BOOL))
)))
(axiom (forall ((Y&. Dcr) (Y& Type) (Z&. Dcr) (Z& Type)) (!
   (=>
    (tr_bound%!T1. Z&. Z& $ INT Y&. Y&)
    (tr_bound%!T2. $ (TYPE%!S. $ (TYPE%tuple%2. Y&. Y& $ (UINT 8))) Z&.
     Z& $ (UINT 16)
   ))
   :pattern ((tr_bound%!T2. $ (TYPE%!S. $ (TYPE%tuple%2. Y&. Y& $ (UINT 8)))
     Z&. Z& $ (UINT 16)
   ))
)))

With this, the axiom for p's broadcast_forall can use the trait bound tr_bound%!T2. as a precondition, so that it only applies to A that satisfy the proper T2 trait bound:

(axiom (forall ((A&. Dcr) (A& Type) (i~2$ Poly)) (!
   (=>
    (has_type i~2$ INT)
    (=>
     (tr_bound%!T2. A&. A& $ (TYPE%!S. $ INT) $ (UINT 16))
     (!f.? A&. A& i~2$)
   ))
   :pattern ((!f.? A&. A& i~2$))
)))

@Chris-Hawblitzel Chris-Hawblitzel deleted the trait_bound_smt_encoding branch August 16, 2023 00:07
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