rust-lang / rust-clippy

A bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/
https://rust-lang.github.io/rust-clippy/
Other
11.46k stars 1.55k forks source link

Lint for named, but unused, futures #8126

Open goffrie opened 2 years ago

goffrie commented 2 years ago

What it does

In some situations, such as async-aware Mutexes, it is useful to call an async function and bind its result to a variable so that it drops at the end of the scope - e.g. let _guard = mutex.lock().await. However, it's probably a mistake to do so without awaiting (or block_on, or otherwise consuming) the Future.

This is a bit rare as you'd usually notice when making use of the returned guard, but not always. This came up today and was a real head-scratcher.

Lint Name

No response

Category

correctness

Advantage

This lint detects an issue that is completely silent at compile time, and hard to detect in tests. (In the mutex example, casual testing may not discover the lack of mutual exclusion at all!)

Drawbacks

This could cause a false positive when calling a (non-async) function that returns a type that implements Future but also has its own nontrivial Drop implementation, that the caller intentionally wants to defer. I'm not aware of any use case where that would apply. In particular, this never applies to an async fn as dropping an async block does nothing except drop its captured arguments.

Example

pub async fn doit(x: std::sync::Arc<tokio::sync::Mutex<()>>) {
    let _foo = x.lock();
    println!("i'm exclusive");
}

Should be instead:

pub async fn doit(x: std::sync::Arc<tokio::sync::Mutex<()>>) {
    let _foo = x.lock().await; // `.await` here
    println!("i'm exclusive");
}
camsteffen commented 2 years ago

So basically detect a Future assigned to a variable but then never used? Name idea: unused_future.