My T generic does implement the conditions on where, but I can't use it

Viewed 79
struct Response {}

struct PlayResponse(Response);
struct DescribeResponse(Response);

impl From<Response> for PlayResponse {
    fn from(response: Response) -> Self {
        PlayResponse(response)
    }
}

enum RtspState {
    Init,
    Playing,
}

struct RtspMachine {
    state: RtspState
}

pub trait OnEvent<T> {
    fn on_event(&mut self, event: &T) -> std::result::Result<(), ()>;
}

impl OnEvent<PlayResponse> for RtspMachine {
    fn on_event(&mut self, event: &PlayResponse) -> std::result::Result<(), ()> {
        self.state = RtspState::Playing;
        Ok(())
    }
}


fn do_something<T: OnEvent<T>>() where RtspMachine: OnEvent<T>, T: From<Response>{
    let mut rtsp_machine = RtspMachine{state: RtspState::Init};
    rtsp_machine.on_event(&T::from(Response{}));
    rtsp_machine.on_event(&PlayResponse::from(Response{}));
}

On the do_something above, we require where RtspMachine: OnEvent<T>, T: From<Response>.

Note that RtspMachine: OnEvent<PlayResponse> and PlayResponse: From<Response>. I should be able to do rtsp_machine.on_event(&PlayResponse::from(Response{}));, but it only works for the version with T.:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:36:27
   |
33 | fn do_something<T: OnEvent<T>>() where RtspMachine: OnEvent<T>, T: From<Response>{
   |                 - this type parameter
...
36 |     rtsp_machine.on_event(&PlayResponse::from(Response{}));
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `PlayResponse`
   |
   = note: expected reference `&T`
              found reference `&PlayResponse`

Rust playground

I know that

fn do_something<T>() where
    RtspMachine: OnEvent<T> + OnEvent<PlayResponse>,
    T: From<Response>

would work but I have lots of T that I wanted to use the specific type instead of generic T, so I can't just put them all on the where like that.

1 Answers

This is a known problem with the compiler's method resolution in the presence of trait bounds (#24066, #38071). Changing your method call

    rtsp_machine.on_event(&PlayResponse::from(Response{}));

to the explicit function call form

    OnEvent::<PlayResponse>::on_event(
        &mut rtsp_machine, &PlayResponse::from(Response{}));

will allow the code to compile. Apparently, in the version that doesn't work, method resolution is looking only at the OnEvent<T> trait that's mentioned in where, even though OnEvent<PlayResponse> also exists.

I don't know if there's a more elegant solution, but perhaps the above will be adequate for your problem — at least it means the extra syntax is local to the call site.

Related