Match arms have incompatible types

Hi,

I'm just starting to learn rust and as a learning project - after reading half of the "Programming Rust" Oreilly book - I'm trying to build some kind of pow / puma-dev but not specific to rails (that means serve local directories and reverse proxy local ports).

The web part of it is to check the Host header on the request, query local state for type of response required (e.g. serve specific directory) and respond accordingly. I tried several ways to achieve this but I always get to incompatible types on match arms. The furthest I got (at least in terms of types that I can understand) is by following and expanding on this example of hyper-staticfile. I more or less copied this implementation and added another item to the MainFuture enum like that:

enum MainFuture {
  Static(StaticFuture<Body>),
  ReverseProxy(BoxFut)
}

Both futures are the result of library calls (hyper-staticfile and hyper-reverse-proxy).

So the Future implementation looks like this:

impl Future for MainFuture {
  type Item = Response<Body>;
  type Error = Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    match *self {
      MainFuture::Static(ref mut future) => future.poll(),
      MainFuture::ReverseProxy(ref mut future) => future.poll(),
    }
  }
}

The problem is that the Static future returns std::io::Error as error type and the reverse proxy returns hyper::Error. Compiling it gets me:

error[E0308]: match arms have incompatible types
  --> src/web/mod.rs:33:51
   |
31 | /     match *self {
32 | |       MainFuture::Static(ref mut future) => future.poll(),
   | |                                             ------------- this is found to be of type `std::result::Result<futures::poll::Async<http::response::Response<hyper::body::body::Body>>, std::io::Error>`
33 | |       MainFuture::ReverseProxy(ref mut future) => future.poll(),
   | |                                                   ^^^^^^^^^^^^^ expected struct `std::io::Error`, found struct `hyper::error::Error`
34 | |     }
   | |_____- `match` arms have incompatible types
   |
   = note: expected type `std::result::Result<_, std::io::Error>`
              found type `std::result::Result<_, hyper::error::Error>`

error: aborting due to previous error

As far as I understand error chaining won't help here as I'm not using ?. Can anyone please help me solve this?

Thanks in advance

Haim

1 Like

You need to convert both error into a custom error type you'll have to define.
I can't stress enough the reading of this blog post that covers Error handling in Rust:

And after, the reading of the failure book:
https://boats.gitlab.io/failure/intro.html

1 Like

Thanks Geobomatic for the interesting links. I didn't know the first one but I do use failure.

I read through the examples of the first article but maybe I miss something. Any kind of error chaining / automatic conversion with From trait only works when using the ? macro or if I return them directly from a function. I don't understand how do I use it in my example unless I can somehow manipulate the Poll result of the provided future.poll() functions.

To make my question even clearer, let's assume MyError is a real error implementing Error, Display and Debug.

consider this function:

fn return_error() -> std::io::Result<()> {
    Err(ioError::new(ErrorKind::AddrInUse, "oh no"))
}

If I'm calling it like this:

fn regular_error() ->  Result<(), MyError> {
    let _x = return_error()?;
    Ok(())
}

then it works without a problem, however if I call it like this:

fn regular_error() ->  Result<(), MyError> {
    return_error()
}

I get a mismatch types error.

The different errors from the future.poll() are returned directly from 3rd party futures. I'm not sure how to manipulate them to return my type of error.

Thanks.

You'll have to code how to convert std::io::Result to MyError by:

impl From<std::io::Error> for MyError { ... }
1 Like

I have the conversion code - here's the complete example of the example I gave:

use std::error::Error;
use std::io::{Error as ioError, ErrorKind};
use std::fmt::{self, Display, Formatter};

#[derive(Debug)]
pub enum MyError {
    Io(ioError)
}

impl Error for MyError {
    fn description(&self) -> &str {
        unimplemented!()
    }
}


impl From<ioError> for MyError {
    fn from(error: ioError) -> Self {
        MyError::Io(error)
    }
}

impl Display for MyError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "an error occurred")
    }
}

fn regular_error() ->  Result<(), MyError> {
    let _x = return_error()?;
    Ok(())
}

fn return_error() -> std::io::Result<()> {
    Err(ioError::new(ErrorKind::AddrInUse, "oh no"))
}

fn main() {
    match regular_error() {
        Ok(()) => println!("success"),
        Err(e) => println!("err: {:#?}", e)
    }
}

It runs perfectly well. However, If I change regular_error to return the result of return_error directly I get this error:

error[E0308]: mismatched types
  --> src/main.rs:30:5
   |
29 | fn regular_error() ->  Result<(), MyError> {
   |                        ------------------- expected `std::result::Result<(), MyError>` because of return type
30 |     return_error()
   |     ^^^^^^^^^^^^^^ expected enum `MyError`, found struct `std::io::Error`
   |
   = note: expected type `std::result::Result<_, MyError>`
              found type `std::result::Result<_, std::io::Error>`

error: aborting due to previous error

I'm probably missing something but I don't know what :slight_smile:

Thanks.

What if you use return_error().into() (and future.poll().into() in your original case)?

the question mark operator ? calls .into() on the error type, hence using your conversion function:

impl From<ioError> for MyError {
    fn from(error: ioError) -> Self {
        MyError::Io(error)
    }
}

In your case, it would have been equivalent to doing:

    return_error().map_err(MyError::from)
2 Likes

Thanks but this doesn't work. If I understand the error correctly I would have to implement From to the Result object, not just the error.

1 Like

[quote="Yandros, post:7, topic:28195, full:true"]

That's it, this solved the problem :slight_smile:.

Thanks a lot, I've been struggling with it for 2 days now.

Haim

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.