Higher-rank trait bound not satisfied

I'm trying to compile this piece of example code:

mod general {
    // Shorthand for getting the OperationState type of an Operation with a given Session type
    pub type StateOf<'s, A, Sess> = <A as HasOperationState<'s, Sess>>::State;

    // Shorthand for getting the Session type of an Operation
    pub type SessionOf<A> = <<A as Operation>::SessionLookup as SessionLookup>::Session;

    pub trait SessionLookup {
        type Session;
    }

    pub trait Operation: for<'s> HasOperationState<'s, SessionOf<Self>> {
        type SessionLookup: SessionLookup + 'static;
    }

    pub trait OperationState<'s, Sess> {
        fn session(&self) -> &Sess;
    }

    pub trait HasOperationState<'s, Sess> {
        type State: OperationState<'s, Sess>;
    }

    pub struct PhantomOperation<T: Operation>(pub ::std::marker::PhantomData<T>);
}

mod specific {
    use crate::general::*;

    pub struct MySession {}

    pub struct MySessionLookup {}

    impl SessionLookup for MySessionLookup {
        type Session = MySession;
    }

    pub trait MyOperationState {}

    pub trait MyExtensionTrait {}

    // This gives a compilation error:
    //
    // type annotations needed: cannot satisfy `<A as general::HasOperationState<'s, extension::MySession>>::State == _`
    impl<'s, A> MyExtensionTrait for PhantomOperation<A>
        where A: Operation<SessionLookup = MySessionLookup> + HasOperationState<'s, MySession>,
              StateOf<'s, A, SessionOf<A>>: MyOperationState,
    {

    }
}

Rust playground link.

This code results in a compiler error that isn't very helpful for me:

type annotations needed: cannot satisfy `<A as general::HasOperationState<'s, extension::MySession>>::State == _`

I already filed a rust bug report about the (un)helpfulness of this error message (it's issue #76870), but now I'd like to figure out why this code doesn't type check.

The code compiles when I change the impl of MyExtensionTrait to:

impl<A> MyExtensionTrait for PhantomOperation<A>
        where A: Operation<SessionLookup = MySessionLookup> + for<'a> HasOperationState<'a, SessionOf<A>>,
              for<'b> StateOf<'b, A, SessionOf<A>>: MyOperationState
    {

    }

but when I then try to instantiate a trait object that implements MyExtensionTrait like so:

struct SomeOperation {}

impl Operation for SomeOperation {
    type SessionLookup = MySessionLookup;
}

struct SomeOperationState {}

impl<'s> OperationState<'s, MySession> for SomeOperationState {
    fn session(&self) -> &MySession { &MySession {} }
}

impl<'s> HasOperationState<'s, MySession> for SomeOperation {
    type State = SomeOperationState;
}

impl MyOperationState for SomeOperationState {}

fn create_my_extension_trait_instance() -> Box<dyn MyExtensionTrait> {
    Box::new(PhantomOperation::<SomeOperation>(Default::default()))
}

The compiler complains that the MyOperationState bound is not satisfied:

error[E0277]: the trait bound `for<'b> <SomeOperation as general::HasOperationState<'b, specific::MySession>>::State: MyOperationState` is not satisfied
  --> src/lib.rs:75:5
   |
75 |     Box::new(PhantomOperation::<SomeOperation>(Default::default()))
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> MyOperationState` is not implemented for `<SomeOperation as general::HasOperationState<'b, specific::MySession>>::State`
   |
   = note: required because of the requirements on the impl of `specific::MyExtensionTrait` for `general::PhantomOperation<SomeOperation>`
   = note: required for the cast to the object type `dyn specific::MyExtensionTrait`

Rust playground link.

I thought the type bound that the compiler is complaining about would be satisfied by this line

impl MyOperationState for SomeOperationState {}

but apparently it's not.

Any ideas on how I could satisfy that type bound, or reformulate the type bounds on the MyExtensionTrait impl to get this to compile?

I managed to work around this problem by rewriting the bounds in the impl of MyExtensionTrait as:

impl<A, S> MyExtensionTrait for PhantomOperation<A>
        where A: Operation<SessionLookup = MySessionLookup> + for<'a> HasOperationState<'a, SessionOf<A>, State = S>,
              S: MyOperationState,
    { }

Rust playground link.

Compared to the original, there's the extra type parameter S, which is bound to HasOperationState::State. The fundamental difference is that there's only a single universally quantified lifetime 'a now, instead of two. My understanding is that when there are two such lifetimes, they don't necessarily have to be equal to each other and hence the compiler cannot satisfy the bound I had written down.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.