Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust: expected type, found opaque type

I wanted to make an auxiliary function for rendering templates in actix, here's how it looks:

fn render_response(
    tera: web::Data<Tera>,
    template_name: &str,
    context: &Context,
) -> impl Responder {
    match tera.render(template_name, context) {
        Ok(rendered) => HttpResponse::Ok().body(rendered),
        Err(_) => HttpResponse::InternalServerError().body("Failed to resolve the template."),
    }
}

I'm using it in views like this one below:

async fn signup(tera: web::Data<Tera>) -> impl Responder {
    let mut data = Context::new();
    data.insert("title", "Sign Up");

    render_response(tera, "signup.html", &data)
}

If the view is as simple as the one above, everything works fine, but if the view is slightly more complicated I get a problem:

async fn login(tera: web::Data<Tera>, id: Identity) -> impl Responder {
    let mut data = Context::new();
    data.insert("title", "Login");

    if let Some(id) = id.identity() {
        return HttpResponse::Ok().body(format!("Already logged in: {}.", id));
    }

    render_response(tera, "login.html", &data)
}

The error I get:

error[E0308]: mismatched types
   --> src\main.rs:101:5
    |
42  | ) -> impl Responder {
    |      -------------- the found opaque type
...
101 |     render_response(tera, "login.html", &data)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `actix_web::HttpResponse`, found opaque type
    |
    = note:     expected type `actix_web::HttpResponse`
            found opaque type `impl actix_web::Responder`

I've tried to extract the return HttpResponse... to a separate function that also returns impl Responder, but I'm getting different error now:

error[E0308]: mismatched types
   --> src\main.rs:101:5
    |
42  | ) -> impl Responder {
    |      -------------- the found opaque type
...
101 |     render_response(tera, "login.html", &data)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
    |
    = note:     expected type `impl actix_web::Responder` (opaque type at <src\main.rs:104:28>)
            found opaque type `impl actix_web::Responder` (opaque type at <src\main.rs:42:6>)
    = note: distinct uses of `impl Trait` result in different opaque types

I don't really understand why it happens and how to fix it.

like image 588
Djent Avatar asked May 25 '26 20:05

Djent


1 Answers

When a function returns something like impl Responder, it means that it returns some type that implements Responder. The compiler can deduce the type, but it is "opaque" to any caller, meaning you can't assume anything about what the type actually is. Even if the compiler has a bit more information, types are always matched at function boundaries. This is important so that humans can reason about the code at the function level, without having to hold all of the information about individual lines of a program in their heads.

A function also must only return one type, so when the compiler comes across a function like this:

async fn login(tera: web::Data<Tera>, id: Identity) -> impl Responder {
    let mut data = Context::new();
    data.insert("title", "Login");

    if let Some(id) = id.identity() {
        return HttpResponse::Ok().body(format!("Already logged in: {}.", id));
    }

    render_response(tera, "login.html", &data)
}

it sees the final statement returning an opaque impl Responder and the early return statement returning a concrete HttpResponse. Even though you know they are actually the same type, that's only because you happen to know how render_response is implemented. This is good because it prevents a change in an unrelated part of your code from breaking this function: you wouldn't want a change to the body of render_response to cause a type mismatch in login.

Change the return type of render_response to the concrete type and it will work:

fn render_response(
    tera: web::Data<Tera>,
    template_name: &str,
    context: &Context,
) -> HttpResponse;
like image 160
Peter Hall Avatar answered May 27 '26 13:05

Peter Hall



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!