Skip to content

Unclear diagnostics for async callback that takes a reference #76609

@panstromek

Description

@panstromek

This code..

pub async fn foo() {
    wrapper(callback).await
}

pub async fn callback(buf: &mut [u8]) {}

pub async fn wrapper< Fun, Fut>(cb: Fun)
    where
        Fun: Fn(& mut [u8]) -> Fut ,
        Fut: Future<Output=()>
{
    let mut buf = [8; 8];
    cb(&mut buf).await
}

...triggers this diagnostic:

error: implementation of `std::ops::FnOnce` is not general enough
   --> tests/src/main.rs:8:5
    |
8   |       wrapper(callback).await
    |       ^^^^^^^ implementation of `std::ops::FnOnce` is not general enough
    | 
   ::: /home/matyas/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:219:1
    |
219 | / pub trait FnOnce<Args> {
220 | |     /// The returned type after the call operator is used.
221 | |     #[lang = "fn_once_output"]
222 | |     #[stable(feature = "fn_once_output", since = "1.12.0")]
...   |
227 | |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
228 | | }
    | |_- trait `std::ops::FnOnce` defined here
    |
    = note: `std::ops::FnOnce<(&'0 mut [u8],)>` would have to be implemented for the type `for<'_> fn(&mut [u8]) -> impl std::future::Future {callback}`, for some specific lifetime `'0`...
    = note: ...but `std::ops::FnOnce<(&mut [u8],)>` is actually implemented for the type `for<'_> fn(&mut [u8]) -> impl std::future::Future {callback}`

and it's completely unclear to me how to fix it. Well, obviously the problem is that the callback takes a reference, but even that took me some time to realize (longer than I'd like to admit). In the end I just removed it and did it differently.

This code came from refactoring of some non-async code, so I for some time I didn't realize that I was doing something fishy. I don't have much experience with async rust, so I don't know if this is even possible to fix while still keeping the reference there (maybe with some clever bounds?). If not, it should probably suggest you to rewrite it to not use that reference.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.D-confusingDiagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions