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

Incorrect "implementation of Send is not general enough" error with lifetimed Send impl used in async fn #96865

Open
SabrinaJewson opened this issue May 9, 2022 · 11 comments
Labels
A-async-await Area: Async & Await A-coroutines Area: Coroutines AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@SabrinaJewson
Copy link
Contributor

I tried this code:

struct Foo<'a, F> {
    func: F,
    data: &'a u32,
}
unsafe impl<'a, F: Send + Callback<&'a u32>> Send for Foo<'a, F> {}

trait Callback<I> {}

struct Implementor<'a>(&'a u32);
impl<'a> Callback<&'a u32> for Implementor<'a> {}

fn assert_send<T: Send>(v: T) -> T { v }

async fn async_function<'a>(data: &'a u32) {
    let data = assert_send(Foo {
        func: Implementor(data),
        data,
    });
    std::future::ready(5).await;
}

fn wrapper(data: &u32) {
    assert_send(async_function(data));
}

I expected to see this happen: No error

Instead, this happened:

error: implementation of `std::marker::Send` is not general enough
  --> src/main.rs:23:5
   |
23 |     assert_send(async_function(data));
   |     ^^^^^^^^^^^ implementation of `std::marker::Send` is not general enough
   |
   = note: `std::marker::Send` would have to be implemented for the type `Foo<'0, Implementor<'1>>`, for any two lifetimes `'0` and `'1`...
   = note: ...but `std::marker::Send` is actually implemented for the type `Foo<'2, Implementor<'_>>`, for some specific lifetime `'2`

Meta

rustc --version --verbose:

rustc 1.60.0 (7737e0b5c 2022-04-04)
binary: rustc
commit-hash: 7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c
commit-date: 2022-04-04
host: x86_64-unknown-linux-gnu
release: 1.60.0
LLVM version: 14.0.0

Also happens with Nightly:

rustc 1.62.0-nightly (bed05e996 2022-05-02)
binary: rustc
commit-hash: bed05e996e37e44b1a3980b84754af621fd3c4ce
commit-date: 2022-05-02
host: x86_64-unknown-linux-gnu
release: 1.62.0-nightly
LLVM version: 14.0.1
@SabrinaJewson SabrinaJewson added the C-bug Category: This is a bug. label May 9, 2022
@aliemjay
Copy link
Member

aliemjay commented May 10, 2022

Minimized: https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=87d7f794697776f806158ef6b9880bdb

struct Foo<'a>(&'a str);
unsafe impl Send for Foo<'static> {}

fn assert_send_future() -> impl Send {
    async {
        let data: Foo<'static> = Foo("");
        std::future::ready(()).await;
    }
}

@rustbot label A-generators A-async-await T-compiler

@rustbot rustbot added A-async-await Area: Async & Await A-coroutines Area: Coroutines T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 10, 2022
@SabrinaJewson
Copy link
Contributor Author

Another instance of what I think is the same bug, this time with dyn Traits and associated types: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6d632d153fdfebd3cb7348a0ec15326a (discovered by @LegionMammal978 on Discord)

trait Funnel {
    type This;
}
impl<T: 'static> Funnel for T {
    type This = T;
}

async fn bar<T: Funnel>() {
    let _x: T::This = todo!();
    std::future::ready(()).await;
}

pub fn test() -> impl Send {
    async { bar::<Box<dyn Send>>().await }
}

The fix there is to wrap the dyn Trait in another type:

#[repr(transparent)]
struct DynSendWrapper(dyn Send);

pub fn test() -> impl Send {
    async { bar::<Box<DynSendWrapper>>().await }
}

@eholk
Copy link
Contributor

eholk commented May 23, 2022

It looks like we are incorrectly replacing regions with inference variables. In generator_interior, it looks like we replace regions with variables in a couple of places for convenience, so maybe we are being sloppy with that? Here are a couple of places that might be relevant:

  1. // Replace all regions inside the generator interior with late bound regions.
    // Note that each region slot in the types gets a new fresh late bound region,
    // which means that none of the regions inside relate to any other, even if
    // typeck had previously found constraints that would cause them to be related.
  2. https://cs.github.com/rust-lang/rust/blob/653463731a7f01f519cf85f444869def27f00395/compiler/rustc_typeck/src/check/generator_interior.rs#L249

@rustbot label AsyncAwait-Triaged

@rustbot rustbot added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label May 23, 2022
@carols10cents
Copy link
Member

Is this related to/duplicate of #64552?

@tmandry tmandry moved this to On deck in wg-async work Dec 8, 2022
@emersonford
Copy link

@carols10cents @eholk yeah this is definitely the same issue as #102211. fixing that bug should fix all related issues.

@zertyz
Copy link

zertyz commented Aug 19, 2023

Please, bump up this bug report.
All the problematic code presented here still show the same errors in Rust 1.71, 1.3 years after.
This bug bit me nowadays, preventing my progress on a nice & flexible generic async code using references for zero-copying things around.
I'll either have to write inneficient code or chase an as-efficient-as-possible workaround for my specific case for hours and hours...

@zertyz
Copy link

zertyz commented Aug 21, 2023

I ended up using the alternative notation -- described here: #102211 (comment) -- to avoid this type inference compiler bug when GATs are involved.
Other zero-cost workarounds are possible as well:

Other workarounds exist in the first link, but they involve paying extra costs for boxing / dynamic dispatching.

@lukaszwojtow
Copy link

I think this: https://github.com/qpackt/qpackt/blob/b4f20dd9f0273ee0c1c33e7b994e7bf8e046cf2d/qpackt-backend/src/main.rs#L93 is also wrong. Should I report it separately or is it the same bug?

AmmarAbouZor added a commit to AmmarAbouZor/chipmunk that referenced this issue Jun 12, 2024
- Changing parser trait to async caused an error in the DLT parser
  because it returns type has a reference in it. Because of that we got
  a compiler error about that the results doesn't implements Send trait
  enough.
- This Error is possible to be a bug in rust that would be fixed in the
  future. See issues:
  - rust-lang/rust#64552
  - rust-lang/rust#96865
- For now I replaced the references with Arcs in the results of
  DLT-Parser
AmmarAbouZor added a commit to AmmarAbouZor/chipmunk that referenced this issue Jun 12, 2024
…in hosts

- Changing parser trait to async caused an error in the DLT parser
  because it returns type has a reference in it. Because of that we got
  a compiler error about that the results doesn't implements Send trait
  enough.
- This Error is possible to be a bug in rust that would be fixed in the
  future. See issues:
  - rust-lang/rust#64552
  - rust-lang/rust#96865
- For now I replaced the references with Arcs in the results of
  DLT-Parser

- implements for parser Plugin hosts now awaits on the async call from
  the plugin instead of using `futures::executer::block_on()`. However,
  this change didn't improve the performance of the plugins
AmmarAbouZor added a commit to AmmarAbouZor/chipmunk that referenced this issue Jun 12, 2024
…in hosts

- Changing parser trait to async caused an error in the DLT parser
  because it returns type has a reference in it. Because of that we got
  a compiler error about that the results doesn't implements Send trait
  enough.
- This Error is possible to be a bug in rust that would be fixed in the
  future. See issues:
  - rust-lang/rust#64552
  - rust-lang/rust#96865
- For now I replaced the references with Arcs in the results of
  DLT-Parser

- implements for parser Plugin hosts now awaits on the async call from
  the plugin instead of using `futures::executer::block_on()`. However,
  this change didn't improve the performance of the plugins
@QuenKar
Copy link

QuenKar commented Jun 26, 2024

I also meet this error with code:

#[allow(unused)]
#[async_trait::async_trait]
pub trait MyTrait {
    async fn do_something(&self);
}

pub struct MyStruct<'a> {
    a: &'a str,
}

unsafe impl Send for MyStruct<'static> {}

pub struct TestStruct;

impl TestStruct {
    async fn function4(_a: &String, _b: MyStruct<'static>) {
        // if not the following line, will get error, but why?
        let _b: MyStruct<'static> = _b;
    }
}

#[async_trait::async_trait]
impl MyTrait for TestStruct {
    async fn do_something(&self) {
        let s: &'static str = "hello world";
        let my_struct: MyStruct<'static> = MyStruct::<'static> { a: s };
        let a = "xxx".to_string();

        Self::function4(&a, my_struct).await;
    }
}

but it can be solved by adding let _b: MyStruct<'static> = _b; , but why?

@rvolosatovs
Copy link

Encountered this issue with rustc 1.78.0 and fixed it using a very simple workaround trait like so:

I've distilled this from observation in #100013 (comment) that calling .boxed() on the future fixes the issue to arrive to something that does not require a heap allocation

pub trait SendFuture: core::future::Future {
    fn send(self) -> impl core::future::Future<Output = Self::Output> + Send
    where
        Self: Sized + Send,
    {
        self
    }
}

impl<T: core::future::Future> SendFuture for T {}

I've published the fix in a send-future crate with docs available at https://docs.rs/send-future/latest/send_future/trait.SendFuture.html

rvolosatovs added a commit to rvolosatovs/wrpc that referenced this issue Jul 5, 2024
fix rust-lang/rust#96865 in bindgen

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
github-merge-queue bot pushed a commit to bytecodealliance/wrpc that referenced this issue Jul 5, 2024
fix rust-lang/rust#96865 in bindgen

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
@problame
Copy link

problame commented Aug 20, 2024

The original minimized versions no longer errors on rustc 1.80.1

However, I just ran into an error like this one with a seemingly benign use of async fn in trait. ENOTIME to minimize it, here's the commit that has the error.

@rvolosatovs 's send-future crate was successfully used to work around the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-coroutines Area: Coroutines AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
Status: On deck
Development

No branches or pull requests