actix / actix-web

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.
https://actix.rs
Apache License 2.0
21.8k stars 1.69k forks source link

Cannot infer type for type parameter when defining handler with #[get("/")] and generics #2866

Open kiokuless opened 2 years ago

kiokuless commented 2 years ago

Expected Behavior

Pass type checking

Current Behavior

error[E0282]: type annotations needed
  --> examples/cannnot-compile.rs:28:10
   |
28 | async fn index<T: UserRepository>(client: web::Data<T>) -> impl Responder {
   |          ^^^^^ cannot infer type for type parameter `T` declared on the function `index`

Some errors have detailed explanations: E0107, E0282.
For more information about an error, try `rustc --explain E0107`.
error: could not compile `my-project` due to 2 previous errors

Possible Solution

Use .route("/", web::get().to(index::<T>) instead of service(index::<T>) and get method macro, but is there any good way to keep using get macro?

Steps to Reproduce (for bugs)

use actix_web::{
    dev::Server,
    get,
    web::{self, Data},
    App, HttpServer, Responder,
};
use serde::Serialize;

#[derive(Debug, Serialize, Clone, Copy)]
pub struct User {
    id: u64,
}

pub trait UserRepository {
    fn get_user(&self) -> User;
}

#[derive(Clone)]
struct UserClient;

impl UserRepository for UserClient {
    fn get_user(&self) -> User {
        User { id: 0 }
    }
}

// when uncommenting following the line, the type checking is unaccepted
// because of cannot infer type parameter T
// #[get("/")]
async fn index<T: UserRepository>(client: web::Data<T>) -> impl Responder {
    let user = client.into_inner().get_user();
    web::Json(user)
}

pub fn create_server<T: UserRepository + Send + Sync + 'static + Clone>(
    search: T,
) -> Result<Server, std::io::Error> {
    let server = HttpServer::new(move || {
        App::new()
            .app_data(Data::new(search.clone()))
            .route("/", web::get().to(index::<T>))
        // .service(index::<T>)
    })
    .bind("127.0.0.1:8080")?
    .run();
    Ok(server)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let user_client = UserClient;
    create_server(user_client).unwrap().await
}

Context

Your Environment

fakeshadow commented 2 years ago

no. the proc macro lack generics handling and it completely ignore syn::FnDecl type. To fix it somebody have to add more code to actix-web-codegen to collect and paste Syn::Generics.

tbh if you can do without proc macro easily it's always a good choice. simple route macro is never a good choice it was just popular at one time and overtime it shows it's limitation.

Courtcircuits commented 4 months ago

Has this issue been resolved ?