`async fn` from Editor to Executable

By Arpad Borsos

Elevator Pitch

What is an async fn, and what does the compiler do with it? Why is the difference between async fn and fn -> impl Future such a footgun? Learn all about this, and how the compiler changes over time to make some of these problems go away.

Description

An async fn that you write goes through different compiler stages, from Editor -> AST -> HIR -> MIR -> Executable. This process is complex and changing all the time. My contribution to this was removing the GenFuture type, which used to be an implementation detail of async Rust. I will give a deep dive into what this was, why it had to go, and the struggles from a contributor perspective in making it go away. A journey through different workarounds that existed temporarily, and are still existing today.

Apart from this, I will also highlight some very common problems that developers may run into when developing async Rust. Why the difference between async fn and fn -> impl Future matters a lot. Why the mem::size_of of Futures is currently a great concern, how to work around that, as well as an outlook on the Future (pun intended) when the compiler will improve and make manual workarounds unnecessary.

Notes

I would like to primarily focus on my involvement with improving async Rust, specifically centered around https://github.com/rust-lang/rust/pull/104321 and some blogposts I have written: https://swatinem.de/blog/async-codegen/ and https://swatinem.de/blog/improving-async-codegen/

Related to this, I want to also highlight some common problems with async Rust and give concrete advice on how to deal with those. These topics are related to some more of my posts: https://swatinem.de/blog/non-lazy-futures/ https://swatinem.de/blog/future-size/

This should give the audience a chance to learn about the inner workings of async, give them some real life gotchas to watch out for, and also highlight the contribution process and challenges while working on the compiler to improve things around async.