rust-lang / rust-lang/rust-clippy

clippy::manual_async_fn suggests code which doesn't compile

Open
#7,052 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug I-false-positive
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Lint name: clippy::manual_async_fn

I tried this code: full source where it happened
reduced example:

use futures::future::Future;
use std::sync::Arc;

struct Runner();

impl Runner {
    fn spawn<T>(&self, _: T)
    where T: Future<Output = ()> + Send + 'static { }
}

pub struct Struct {
    runner: Arc<Runner>,
}

impl Struct {
    fn fn1(self: Arc<Self>) -> impl Future<Output = ()> + Send + 'static {
        async move {
            self.fn2().await;
        }
    }

    pub async fn fn2(self: Arc<Self>) {
        self.runner.spawn(self.clone().fn1());
    }
}

I expected to see this happen: the lint trigger and give an output that compile, or does not trigger

Instead, this happened: the lint trigger, but the proposed modification does not compile

Error reported when changes are made for project
error[E0391]: cycle detected when computing type of `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes::{opaque#0}`
   --> src/rpc/membership.rs:372:79
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |                                                                                  ^
    |
note: ...which requires borrow-checking `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes`...
   --> src/rpc/membership.rs:372:2
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes`...
   --> src/rpc/membership.rs:372:2
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes`...
   --> src/rpc/membership.rs:372:2
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes`...
   --> src/rpc/membership.rs:372:2
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes`...
   --> src/rpc/membership.rs:372:2
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes`...
   --> src/rpc/membership.rs:372:2
    |
372 |     async fn ping_nodes(self: Arc<Self>, peers: Vec<(SocketAddr, Option<UUID>)>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires evaluating trait selection obligation `impl futures::Future: std::marker::Send`...
note: ...which requires computing type of `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up::{opaque#0}`...
   --> src/rpc/membership.rs:490:7
    |
490 |     ) -> Result<Message, Error> {
    |          ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires borrow-checking `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up`...
   --> src/rpc/membership.rs:487:2
    |
487 | /     async fn handle_advertise_nodes_up(
488 | |         self: Arc<Self>,
489 | |         adv: &[AdvertisedNode],
490 | |     ) -> Result<Message, Error> {
    | |_______________________________^
note: ...which requires processing `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up`...
   --> src/rpc/membership.rs:487:2
    |
487 | /     async fn handle_advertise_nodes_up(
488 | |         self: Arc<Self>,
489 | |         adv: &[AdvertisedNode],
490 | |     ) -> Result<Message, Error> {
    | |_______________________________^
note: ...which requires processing MIR for `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up`...
   --> src/rpc/membership.rs:487:2
    |
487 | /     async fn handle_advertise_nodes_up(
488 | |         self: Arc<Self>,
489 | |         adv: &[AdvertisedNode],
490 | |     ) -> Result<Message, Error> {
    | |_______________________________^
note: ...which requires unsafety-checking `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up`...
   --> src/rpc/membership.rs:487:2
    |
487 | /     async fn handle_advertise_nodes_up(
488 | |         self: Arc<Self>,
489 | |         adv: &[AdvertisedNode],
490 | |     ) -> Result<Message, Error> {
    | |_______________________________^
note: ...which requires building MIR for `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up`...
   --> src/rpc/membership.rs:487:2
    |
487 | /     async fn handle_advertise_nodes_up(
488 | |         self: Arc<Self>,
489 | |         adv: &[AdvertisedNode],
490 | |     ) -> Result<Message, Error> {
    | |_______________________________^
note: ...which requires type-checking `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::handle_advertise_nodes_up`...
   --> src/rpc/membership.rs:487:2
    |
487 | /     async fn handle_advertise_nodes_up(
488 | |         self: Arc<Self>,
489 | |         adv: &[AdvertisedNode],
490 | |     ) -> Result<Message, Error> {
    | |_______________________________^
    = note: ...which requires evaluating trait selection obligation `impl futures::Future: std::marker::Send`...
    = note: ...which again requires computing type of `membership::<impl at src/rpc/membership.rs:224:1: 698:2>::ping_nodes::{opaque#0}`, completing the cycle
    = note: cycle used when evaluating trait selection obligation `impl futures::Future: std::marker::Send`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0391`.
Error reported when changes are made for reduced example
error[E0391]: cycle detected when computing type of `<impl at src/lib.rs:15:1: 25:2>::fn2::{opaque#0}`
  --> src/lib.rs:22:39
   |
22 |     pub async fn fn2(self: Arc<Self>) {
   |                                       ^
   |
note: ...which requires borrow-checking `<impl at src/lib.rs:15:1: 25:2>::fn2`...
  --> src/lib.rs:22:5
   |
22 |     pub async fn fn2(self: Arc<Self>) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `<impl at src/lib.rs:15:1: 25:2>::fn2`...
  --> src/lib.rs:22:5
   |
22 |     pub async fn fn2(self: Arc<Self>) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `<impl at src/lib.rs:15:1: 25:2>::fn2`...
  --> src/lib.rs:22:5
   |
22 |     pub async fn fn2(self: Arc<Self>) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `<impl at src/lib.rs:15:1: 25:2>::fn2`...
  --> src/lib.rs:22:5
   |
22 |     pub async fn fn2(self: Arc<Self>) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: ...which requires evaluating trait selection obligation `impl futures::Future: std::marker::Send`...
   = note: ...which again requires computing type of `<impl at src/lib.rs:15:1: 25:2>::fn2::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
  --> src/lib.rs:1:1
   |
1  | / use futures::future::Future;
2  | | use std::sync::Arc;
3  | |
4  | | struct Runner();
...  |
24 | |     }
25 | | }
   | |_^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0391`.
Meta
  • cargo clippy -V: nigtly clippy 0.1.52 (07e0e2e 2021-03-24)
  • rustc -Vv:
rustc 1.53.0-nightly (07e0e2ec2 2021-03-24)
binary: rustc
commit-hash: 07e0e2ec268c140e607e1ac7f49f145612d0f597
commit-date: 2021-03-24
host: x86_64-unknown-linux-gnu
release: 1.53.0-nightly
LLVM version: 12.0.0

(reproducible on latest stable)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reduced Rust example in the issue and reproduce the clippy::manual_async_fn suggestion using the reported Rust and Clippy versions. Inspect the lint's suggestion behavior for the recursive async future case; done means the suggested code compiles, or the lint no longer triggers for this pattern.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.