Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

^^^^^^^ expected (), found Result<ServiceResponse<B>, _> ??? not related not informative .. #115405

Closed
meiry opened this issue Aug 31, 2023 · 6 comments · Fixed by #120696
Closed
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@meiry
Copy link

meiry commented Aug 31, 2023

Code

//main.rs
use actix_web::{get,web,http,Result,App,HttpServer,HttpRequest, Responder, HttpResponse};
use serde::{Deserialize,Serialize};
use actix_cors::Cors;

mod heartbeat;

static PORT :u16 = 9091;

#[get("/")]
async fn index()->impl Responder {
    
    HttpResponse::Ok().body("template")
}

 

#[derive(Serialize)]
pub struct Response {
    pub message: String,
}

async fn not_found() ->Result<HttpResponse> {
    let response = Response {
        message: "Resource not found".to_string(),
    };
    Ok(HttpResponse::NotFound().json(response))
}


#[actix_web::main]
async fn main()-> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "debug");
    env_logger::init();
    HttpServer::new(|| App::new()
    .wrap(
        Cors::default()
            .allowed_origin("http://*") // Allow all http origins
            .allowed_origin("https://*") // Allow all https origins
            .allowed_methods(vec!["GET","POST","PUT","DELETE","OPTIONS"])
            .allowed_headers(vec![http::header::AUTHORIZATION,http::header::CONTENT_TYPE,
                http::header::ACCEPT,http::header::LINK])
            .allowed_header("X-CSRF-TOKEN")
            .supports_credentials()
            .max_age(300)
    )
    .wrap(heartbeat::Heartbeat)
    .service(index)
    .service(web::resource("/ping"))
    .default_service(web::route().to(not_found)))
    .bind(("127.0.0.1",PORT))?
    .run()
    .await        
}


//heartbeat.rs

use std::future::{ready, Ready};

use actix_http::header::{HeaderValue, HeaderName};
use actix_web::{
    dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
    Error,http::Method
};
use futures_util::future::LocalBoxFuture;
//use crate::constants;

pub struct Heartbeat;

impl<S, B> Transform<S, ServiceRequest> for Heartbeat
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = HeartMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ready(Ok(HeartMiddleware { service }))
    }
}

pub struct HeartMiddleware<S> {
    service: S,
}


impl<S, B> Service<ServiceRequest> for HeartMiddleware<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    dev::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        

        let fut = self.service.call(req);
        
        

        Box::pin(async move {
            
            let mut res = fut.await?;
            let headers = res.headers_mut();
            headers.insert(
                 HeaderName::from_static("Content-Type"), HeaderValue::from_static("text/plain")
             );
            
            if (Method::POST == req.method() || 
                 Method::GET  == req.method()  ||
                 Method::HEAD == req.method()) && req.path() == "/ping" {
                 Ok(res)
            }
             
            Err(actix_web::error::ErrorImATeapot("Tea"))
        })
    }
}

Current output

cargo build
   Compiling broker-service v0.1.0 (C:\dev\my\rust\workspace\broker-service)
warning: unused import: `HttpRequest`
 --> src\main.rs:1:52
  |
1 | use actix_web::{get,web,http,Result,App,HttpServer,HttpRequest, Responder, HttpResponse};
  |                                                    ^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `Deserialize`
 --> src\main.rs:2:13
  |
2 | use serde::{Deserialize,Serialize};
  |             ^^^^^^^^^^^

error[E0308]: mismatched types
  --> src\heartbeat.rs:65:18  
   |
62 | /             if (Method::POST == req.method() ||
63 | |                  Method::GET  == req.method()  ||
64 | |                  Method::HEAD == req.method()) && req.path() == "/ping" {
65 | |                  Ok(res)
   | |                  ^^^^^^^ expected `()`, found `Result<ServiceResponse<B>, _>`
66 | |             }
   | |_____________- expected this to be `()`
   |
   = note: expected unit type `()`
                   found enum `Result<ServiceResponse<B>, _>`
note: return type inferred to be `()` here
  --> src\heartbeat.rs:56:27
   |
56 |             let mut res = fut.await?;
   |                           ^^^^^^^^^^

For more information about this error, try `rustc --explain E0308`.
warning: `broker-service` (bin "broker-service") generated 2 warnings
error: could not compile `broker-service` (bin "broker-service") due to previous error; 2 warnings emitted

Desired output

the real Cause for the error 
what is :
^^^^^^^ expected `()`, found `Result<ServiceResponse<B>, _>` ???

Rationale and extra context

using letest actix-web

Other cases

No response

Anything else?

No response

@meiry meiry added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 31, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 31, 2023
@ShE3py
Copy link
Contributor

ShE3py commented Aug 31, 2023

An else block is required:

if [Method::POST, Method::GET, Method::HEAD].contains(req.method()) && req.path() == "/ping" {
    Ok(res)
}
else {
    Err(actix_web::error::ErrorImATeapot("Tea"))
}

See E0317.

@meiry
Copy link
Author

meiry commented Aug 31, 2023

@ShE3py did you test it ? i guess not ,
The problem was that the "req" object got somehow consort and not available ,
if you do :

fn call(&self, req: ServiceRequest) -> Self::Future {
        
        let condition = (Method::POST == req.method() || 
                 Method::GET  == req.method()  ||
                 Method::HEAD == req.method()) && req.path() == "/ping";  

        let condition = (Method::POST == req.method() || 
        Method::GET  == req.method()  ||
        Method::HEAD == req.method()) && req.path() == "/ping";                       
            

        let fut = self.service.call(req);
        Box::pin(async move {
            
            let mut res = fut.await?;

            let CONTANT_TYPE: &'static str = "content-type";
            let TEXT_PLAIN: &'static str = "text/plain";

            let headers = res.headers_mut();
            headers.insert(
                 HeaderName::from_static(CONTANT_TYPE), HeaderValue::from_static(TEXT_PLAIN)
             );
            
            if condition {
                return Ok(res)
            }          
            Err(actix_web::error::ErrorImATeapot("Tea"))
        })
    }

all working 

@Taaitaaiger
Copy link

You either need to write return Ok(res) or add the else block so both the if and else blocks return the same type.

@meiry
Copy link
Author

meiry commented Sep 1, 2023

@Taaitaaiger not working in this case of actix_web

@Noratrieb Noratrieb removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Sep 4, 2023
@kusabana
Copy link
Contributor

kusabana commented Sep 6, 2023

@Taaitaaiger not working in this case of actix_web

I don't quite understand?
Replicating your issue, adding an else block like

if (Method::POST == req.method() || 
     Method::GET  == req.method()  ||
     Method::HEAD == req.method()) && req.path() == "/ping" {
     Ok(res)
} else {
    Err(actix_web::error::ErrorImATeapot("Tea"))
}

solves the error you posted, however this uncovers a new error due to you using a value after move.

@estebank
Copy link
Contributor

estebank commented Feb 5, 2024

@compiler-errors this is the issue I was mentioning just now. Returning the Ok(_) would be correct, because return corresponds to the async block, not the whole function, but we use the same logic both for checking whether return would be appropriate in its scope and to find the enclosing return type. I'm looking into it and trying to fix this today.

@estebank estebank self-assigned this Feb 6, 2024
estebank added a commit to estebank/rust that referenced this issue Feb 6, 2024
When encountering a tail expression in the then arm of an `if` expression
without an `else` arm, account for `async fn` and `async` blocks to
suggest `return`ing the value and pointing at the return type of the
`async fn`.

We now also account for AFIT when looking for the return type to point at.

Fix rust-lang#115405.
estebank added a commit to estebank/rust that referenced this issue Feb 6, 2024
When encountering a tail expression in the then arm of an `if` expression
without an `else` arm, account for `async fn` and `async` blocks to
suggest `return`ing the value and pointing at the return type of the
`async fn`.

We now also account for AFIT when looking for the return type to point at.

Fix rust-lang#115405.
estebank added a commit to estebank/rust that referenced this issue Feb 8, 2024
When encountering a tail expression in the then arm of an `if` expression
without an `else` arm, account for `async fn` and `async` blocks to
suggest `return`ing the value and pointing at the return type of the
`async fn`.

We now also account for AFIT when looking for the return type to point at.

Fix rust-lang#115405.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 13, 2024
Properly handle `async` block and `async fn` in `if` exprs without `else`

When encountering a tail expression in the then arm of an `if` expression without an `else` arm, account for `async fn` and `async` blocks to suggest `return`ing the value and pointing at the return type of the `async fn`.

We now also account for AFIT when looking for the return type to point at.

Fix rust-lang#115405.
@bors bors closed this as completed in 37d2ea2 Feb 13, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 13, 2024
Rollup merge of rust-lang#120696 - estebank:issue-115405, r=oli-obk

Properly handle `async` block and `async fn` in `if` exprs without `else`

When encountering a tail expression in the then arm of an `if` expression without an `else` arm, account for `async fn` and `async` blocks to suggest `return`ing the value and pointing at the return type of the `async fn`.

We now also account for AFIT when looking for the return type to point at.

Fix rust-lang#115405.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants