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

for<'a> Send is distinct from Send? #71462

Open
sfackler opened this issue Apr 23, 2020 · 5 comments
Open

for<'a> Send is distinct from Send? #71462

sfackler opened this issue Apr 23, 2020 · 5 comments
Labels
A-lifetimes Area: Lifetimes / regions A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sfackler
Copy link
Member

This code fails to compile with a pretty strange error:

use std::future::Future;
use std::pin::Pin;
use std::io::Read;

trait Service<R> {
    type Response;
    type Error;
    type Future: Future<Output = Result<Self::Response, Self::Error>>;
    
    fn call(&mut self, req: R) -> Self::Future;
}

struct BorrowerService<S> {
    service: Option<S>,
}

impl<S> Service<Box<dyn Read + Sync + Send>> for BorrowerService<S>
where
    for<'b> S: Service<&'b (dyn Read + 'static + Sync + Send), Response = i32, Error = ()> + 'static + Send,
    for<'b> <S as Service<&'b (dyn Read + 'static + Sync + Send)>>::Future: Send,
{
    type Response = i32;
    type Error = ();
    type Future = Pin<Box<dyn Future<Output = Result<i32, ()>> + Send>>;
    
    fn call(&mut self, req: Box<dyn Read + Sync + Send>) -> Self::Future {
        let mut service = self.service.take().unwrap();
        Box::pin(async move {
            service.call(&req).await
        })
    }
}
error[E0308]: mismatched types
  --> src/lib.rs:28:9
   |
28 | /         Box::pin(async move {
29 | |             service.call(&req).await
30 | |         })
   | |__________^ one type is more general than the other
   |
   = note: expected type `std::marker::Send`
              found type `for<'b> std::marker::Send`

The use of the trait object appears to be important - if I replace that with e.g. String, it compiles just fine:

use std::future::Future;
use std::pin::Pin;

trait Service<R> {
    type Response;
    type Error;
    type Future: Future<Output = Result<Self::Response, Self::Error>>;
    
    fn call(&mut self, req: R) -> Self::Future;
}

struct BorrowerService<S> {
    service: Option<S>,
}

impl<S> Service<Box<String>> for BorrowerService<S>
where
    for<'b> S: Service<&'b String, Response = i32, Error = ()> + 'static + Send,
    for<'b> <S as Service<&'b String>>::Future: Send,
{
    type Response = i32;
    type Error = ();
    type Future = Pin<Box<dyn Future<Output = Result<i32, ()>> + Send>>;
    
    fn call(&mut self, req: Box<String>) -> Self::Future {
        let mut service = self.service.take().unwrap();
        Box::pin(async move {
            service.call(&req).await
        })
    }
}
@sfackler sfackler added the C-bug Category: This is a bug. label Apr 23, 2020
@jonas-schievink jonas-schievink added A-lifetimes Area: Lifetimes / regions A-traits Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 23, 2020
@lcnr
Copy link
Contributor

lcnr commented Apr 23, 2020

somewhat minimized

use std::future::Future;

trait Service<R> {
    type Future: Future<Output = i32>;
    
    fn call(&mut self, req: R) -> Self::Future;
}

struct BorrowerService<S> {
    service: Option<S>,
}

impl<S> Service<Box<dyn Sync + Send>> for BorrowerService<S>
where
    for<'b> S: Service<&'b (dyn 'static + Sync + Send)> + 'static + Send,
    for<'b> <S as Service<&'b (dyn 'static + Sync + Send)>>::Future: Send,
{
    type Future = Box<dyn Future<Output = i32> + Send>;
    
    fn call(&mut self, req: Box<dyn Sync + Send>) -> Self::Future {
        let mut service = self.service.take().unwrap();
        Box::new(async move {
            service.call(&req).await
        })
    }
}

@eddyb
Copy link
Member

eddyb commented Apr 27, 2020

cc @rust-lang/wg-traits

@sfackler
Copy link
Member Author

sfackler commented Oct 7, 2020

Here's a variant that doesn't involve trait objects at all:

trait Service<R> {
    type Future;
}

struct Inner;

impl<R> Service<R> for Inner {
    type Future = ();
}

struct Outer<S> {
    inner: S,
}

impl<S> Service<()> for Outer<S>
where
    for<'a> S: Service<&'a ()>,
    for<'a> <S as Service<&'a ()>>::Future: Send,
{
    type Future = ();
}

fn is_service<S>(_: S)
where
    S: Service<()>
{}

fn main() {
    is_service(Outer { inner: Inner })
}
error[E0277]: `<Inner as Service<&'a ()>>::Future` cannot be sent between threads safely
  --> src/main.rs:29:5
   |
23 | fn is_service<S>(_: S)
   |    ---------- required by a bound in this
24 | where
25 |     S: Service<()>
   |        ----------- required by this bound in `is_service`
...
29 |     is_service(Outer { inner: Inner })
   |     ^^^^^^^^^^ `<Inner as Service<&'a ()>>::Future` cannot be sent between threads safely
   |
   = help: the trait `for<'a> std::marker::Send` is not implemented for `<Inner as Service<&'a ()>>::Future`
   = note: required because of the requirements on the impl of `Service<()>` for `Outer<Inner>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

The error seems bogus, since Inner's future type is (), which is definitely Send, but for<'a> Send is apparently not the same thing!

@sfackler sfackler changed the title expected type Send found type for<'a> Send when trait objects are involved for<'a> Send is distinct from Send? Oct 7, 2020
@lcnr
Copy link
Contributor

lcnr commented Oct 7, 2020

It looks to me like the issue is that we do not normalize projections which are inside of binders, so we are currently unable to normalize for<'a> <ConcreteTy as Trait<'a>>::Assoc until 'a is replaced with a concrete lifetime.

While I would be interested in implementing normalization inside of binders, I do not think that we currently have the capacity to do so.

@sfackler
Copy link
Member Author

sfackler commented Jul 7, 2023

It looks like this has been at least partially fixed. The reproducer without trait objects compiles successfully today, while the original example fails with a different error that sounds a bit like #102211

error: higher-ranked lifetime error
  --> src/lib.rs:28:9
   |
28 | /         Box::pin(async move {
29 | |             service.call(&req).await
30 | |         })
   | |__________^
   |
   = note: could not prove `Pin<Box<[async block@src/lib.rs:28:18: 30:10]>>: CoerceUnsized<Pin<Box<(dyn Future<Output = Result<i32, ()>> + Send + 'b)>>>`

error: could not compile `playground` (lib) due to previous error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants