Impl Trait problems with pattern matching


#1

I am trying to use “Impl Trait” to replace BoxFuture in “https://github.com/tokio-rs/tokio-socks5/blob/master/src/main.rs”. I use “Impl Trait” like the following,

fn serve(self, stream: TcpStream) -> BoxFuture<(), Error> {
    info!("client {:?} connected.", self.address);
    read_exact(stream, [0u8])
        .map_err(|_| "cannot read version number".into())
        .and_then(|(stream, bs)| {
        debug!("client request version {:?}", bs);
        match bs[0] {
            v5::VERSION => self.serve_v5(stream),
            v4::VERSION => self.serve_v4(stream),
            _ => future::err("invalid version number".into()).boxed(),
        }
    }).boxed()
}

fn serve_v5(self, stream: TcpStream) -> impl Future<Item = (), Error = Error> {
    info!("handling version 5 request");
    future::ok(())
}

fn serve_v4(self, _stream: TcpStream) -> impl Future<Item = (), Error = Error> {
    future::err("version 4 unimplemented!".into())
}

The compiler complains that

error[E0308]: match arms have incompatible types
–> src/main.rs:79:13
|
79 | match bs[0] {
| ^ starting here…
80 | | v5::VERSION => self.serve_v5(stream),
81 | | v4::VERSION => self.serve_v4(stream),
82 | | _ => future::err(“invalid version number”.into()).boxed(),
83 | | }
| |
^ …ending here: expected anonymized type, found a different anonymized type
|
= note: expected type impl futures::Future (anonymized type)
found type impl futures::Future (anonymized type)
note: match arm with an incompatible type
–> src/main.rs:81:32
|
81 | v4::VERSION => self.serve_v4(stream),
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

It looks like serve_v4 and serve_v5 are nearly identical. I am not sure why I got mismatched arms. Need someone to shed some lights on it. Thanks in advance.


#2

This is quite expected. impl Trait is conceptually handled similar to generics (even though the true type is known in advance), so even though it might be true that two functions actually return the same underlying type, the compiler considers them to be different. The RFC gives the exact semantics and rationale for that.

Answering to the original question, you should box them. Also I’m pretty sure that your eventual implementations of serve_v4 and serve_v5 won’t return the same types.


#3

It’s clear to me now. I was kind of confused with the Trait and the real type of return value. Thank you very much :slight_smile: