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

Warn when awaiting with other futures in scope #77448

Closed
bugaevc opened this issue Oct 2, 2020 · 1 comment
Closed

Warn when awaiting with other futures in scope #77448

bugaevc opened this issue Oct 2, 2020 · 1 comment

Comments

@bugaevc
Copy link

bugaevc commented Oct 2, 2020

In programming languages where futures are callback-based and can make progress by themselves without anyone actively awaiting them, the following pattern is common for starting several actions concurrently, and waiting then for them all to complete:

future1 = do_something_async1()
future2 = do_something_async2()

res1 = await future1
res2 = await future2

However if you write code like that in Rust, the actions will be executed sequentially, since Rust futures require you to actively poll them to drive them to completion, and you won't be polling future2 while you're .awaiting future1.

Currently, the compiler does not warn on the following code:

let future1 = async { };
let future2 = async { };

future1.await;
future2.await;

(playground)

It would be nice if the compiler could catch situations like these and suggest to use futures::join() instead.

As a first approximation, the heuristic could be: warn if .await is used when a variable whose type is a Future is in scope (and is not the value being awaited) — meaning that other future won't make progress while we're awaiting this one. So in the example above, future1.await is performed while future2 is in scope.

This heuristic would not catch (false negative) the following pattern:

let futures: Vec<SomeFuture> = iter.map(make_future).collect();
for future in futures {
    future.await;
}

which, in other languages, is also a common pattern to preform and await a dynamic number of actions concurrently. In Rust, you have to use something like futures::join_all() or FuturesUnordered.

False positives (where you don't actually have to poll your future for it to make progress):

  • Join handles of spawned tasks
  • Channel receivers
  • Timers

Perhaps there could be an attribute to mark these types.

Related: rust-lang/wg-async#16; but that RFC is about specially marking some types that should not be held across .await, whereas this issue is about applying that to (almost) all futures.

@jonas-schievink
Copy link
Contributor

This seems like it should also go through an RFC, just like rust-lang/wg-async#16, so closing in favor of that.

It is also an option to contribute such a lint to Clippy first, especially since it would have some false positives as you mentioned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants