typesrusttype-annotationrust-warp

Warp asks for absurdly long and complex explicit type annotations, is there another way?


I'm getting the following error,

error[E0283]: type annotations needed for `warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::Filter+std::marker::Copy, impl warp::Filte
r+std::marker::Copy>, impl warp::Filter+std::marker::Copy>, [closure@src/http.rs:12:13: 24:4]>`
  --> src/http.rs:12:4
   |
9  |     let create_user = warp::post()
   |         ----------- consider giving `create_user` the explicit type `warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::Filter+std:
:marker::Copy, impl warp::Filter+std::marker::Copy>, impl warp::Filter+std::marker::Copy>, [closure@src/http.rs:12:13: 24:4]>`, with the type parameters specified
...
12 |         .and_then(|user: super::user::User| async move {
   |          ^^^^^^^^ cannot infer type
   |
   = note: cannot satisfy `_: reject::sealed::CombineRejection<Rejection>`

This is what I wrote. I'm confused at how this is supposed to look,

pub async fn users() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
  let create_user = warp::post()
    .and(warp::path::end())
    .and(warp::body::json())
    .and_then(|user: super::user::User| async move {
      match &user.id_user {
        None => {
          if let Ok(u) = user.insert().await {
            Ok(warp::reply::json(&u))
          }
          else {
            Ok(warp::reply::json(&"FOO".to_owned()))
          }
        }
        Some(_) => Ok(warp::reply::json(&"FOO".to_owned())),
      }
    });

  let routes = warp::path("users");
  routes.and(create_user)
}

How is this supposed to look, am I really supposed to use an explicit type like,

warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::Filter+std::marker::Copy, impl warp::Filter+std::marker::Copy>, impl warp::Filter+std::marker::Copy>

Just to be clear what I want here, is a create user end point.

How can I make sense of the absurdly complex type annotations that Warp is requesting? Is this really required, or am I making mistake?


Solution

  • The issue here is failing type inference for the async block in the and_then() closure. There is no Err() path which would tell the compiler what the Error variant would be, thus the inference fails. You can fix this by annotating the full Result type on one of the return branches:

    Ok::<_, warp::Rejection>(warp::reply::json(&u))
    

    For additional reference:

    https://users.rust-lang.org/t/async-function-parameter-results-in-type-annotation-error/45379

    and a workaround for similar issue about using ? in async blocks:

    https://rust-lang.github.io/async-book/07_workarounds/02_err_in_async_blocks.html