TryInto trait asks for more type annotations even though all annotations are in place

270 Views Asked by At

I have the following code (constrained example). There is a serial protocol, modelled with Command and Responce enums using enum_dispatch crate - every variant in enum is represented with a struct. Transport struct taskes care of serialization, execution and deserialization of Commands, returning TransportResults back with generic Responce enum(generic impl) or specific struct(templated impl). The generic implementation works just fine, but the templated one fails to compile.

use enum_dispatch::enum_dispatch;
use thiserror::Error;

trait Value{/**/}
trait CommandResponce {type Responce}

#[enum_dipatch(Value)]
enum Command{
    Cmd1(Cmd1)
    // ...
}

struct Cmd1{}
impl Value for Cmd1{ /**/ }

#[enum_dipatch(Value)]
enum Responce{
    Resp1(Resp1)
     // ...
}

struct Resp1{}
impl Value for Resp1{/**/}

impl CommandResponce for Cmd1{ type Responce=Resp1 }

#[derive(Error, Debug)]
pub enum ProtocolError{/**/}
type ProtocolResult<T> = Result<T, ProtocolError>;

struct Transport {/**/}
impl Transport {
    // generic
    pub fn command_generic_with_addr(
            &mut self, addr: &mut u8, c: Command
    ) -> ProtocolResult<Responce>{ /**/ }

    // templated
    pub fn command_with_addr<T: SerializeCommand + CommandResponce>(
        &mut self, addr: &mut u8, c: T) -> ProtocolResult<T::Responce>
    where 
        Command: From<T>, Responce: TryInto<T::Responce, Error=&'static str>, 
        Responce: TryInto<T::Responce, Error= CommandErrors> {
        let resp: Responce = self.command_generic_with_addr(addr, Command::from(c))?;
        let ret: T::Responce =  resp.try_into()?;
        Ok(ret)
    }
}


fn main() -> eyre::Result<()>{
   let t = Transport::new();
   let addr : u8 = 0xFF;
   t.command_with_addr(&mut addr, Cmd1{/**/})
}

When I try to compile code, identical to the one above, I get the following error:

error[E0284]: type annotations needed: cannot satisfy `<Responce as TryInto<<T as CommandResponce>::Responce>>::Error == _`
  --> 
   |
85 |         let ret: T::Responce = match resp.try_into()  {
   |                                           ^^^^^^^^ cannot satisfy `<Responce as TryInto<<T as CommandResponce>::Responce>>::Error == _`

I can't understand, what is the error here - I thought I've stated all the neccessary type annotations in the Transport::command_with_addr member function.

Note, enum_dispatch uses the following code to generate try_into conversion, used in the code above:

impl #impl_generics core::convert::TryInto<#variant_type> for #enumname #ty_generics #where_clause {
   type Error = &'static str;
   fn try_into(self) -> ::core::result::Result<#variant_type, <Self as core::convert::TryInto<#variant_type>>::Error> {
       //..
   }
}
0

There are 0 best solutions below