about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStan Manilov <stanislav.manilov@gmail.com>2025-06-02 17:16:29 +0300
committerGitHub <noreply@github.com>2025-06-02 17:16:29 +0300
commit63ecc0ed08ec4e00a720f2ad7db75e8f6ceaac86 (patch)
treedced44043fd976d33a0c8fa1d94af429f1fd8957
parentd6cc62c8c50a5eb45372dc6c97bf76601653f028 (diff)
downloadrust-63ecc0ed08ec4e00a720f2ad7db75e8f6ceaac86.tar.gz
rust-63ecc0ed08ec4e00a720f2ad7db75e8f6ceaac86.zip
Add title and toc to Async chapter
This is standard for other chapters.
-rw-r--r--src/doc/rustc-dev-guide/src/coroutine-closures.md22
1 files changed, 13 insertions, 9 deletions
diff --git a/src/doc/rustc-dev-guide/src/coroutine-closures.md b/src/doc/rustc-dev-guide/src/coroutine-closures.md
index 04742d03c50..314bd13b0a2 100644
--- a/src/doc/rustc-dev-guide/src/coroutine-closures.md
+++ b/src/doc/rustc-dev-guide/src/coroutine-closures.md
@@ -1,6 +1,10 @@
+# Async closures/"coroutine-closures"
+
+<!-- toc -->
+
 Please read [RFC 3668](https://rust-lang.github.io/rfcs/3668-async-closures.html) to understand the general motivation of the feature. This is a very technical and somewhat "vertical" chapter; ideally we'd split this and sprinkle it across all the relevant chapters, but for the purposes of understanding async closures *holistically*, I've put this together all here in one chapter.
 
-# Coroutine-closures -- a technical deep dive
+## Coroutine-closures -- a technical deep dive
 
 Coroutine-closures are a generalization of async closures, being special syntax for closure expressions which return a coroutine, notably one that is allowed to capture from the closure's upvars.
 
@@ -8,7 +12,7 @@ For now, the only usable kind of coroutine-closure is the async closure, and sup
 
 As a consequence of the code being somewhat general, this document may flip between calling them "async closures" and "coroutine-closures". The future that is returned by the async closure will generally be called the "coroutine" or the "child coroutine".
 
-## HIR
+### HIR
 
 Async closures (and in the future, other coroutine flavors such as `gen`) are represented in HIR as a `hir::Closure` whose closure-kind is `ClosureKind::CoroutineClosure(_)`[^k1], which wraps an async block, which is also represented in HIR as a `hir::Closure`) and whose closure-kind is `ClosureKind::Closure(CoroutineKind::Desugared(_, CoroutineSource::Closure))`[^k2].
 
@@ -24,7 +28,7 @@ Like `async fn`, when lowering an async closure's body, we need to unconditional
 
 [^l3]: <https://github.com/rust-lang/rust/blob/5ca0e9fa9b2f92b463a0a2b0b34315e09c0b7236/compiler/rustc_hir_typeck/src/upvar.rs#L250-L256>
 
-## `rustc_middle::ty` Representation
+### `rustc_middle::ty` Representation
 
 For the purposes of keeping the implementation mostly future-compatible (i.e. with gen `|| {}` and `async gen || {}`), most of this section calls async closures "coroutine-closures".
 
@@ -72,7 +76,7 @@ To most easily construct the `Coroutine` that a coroutine-closure returns, you c
 
 Most of the args to that function will be components that you can get out of the `CoroutineArgs`, except for the `goal_kind: ClosureKind` which controls which flavor of coroutine to return based off of the `ClosureKind` passed in -- i.e. it will prepare the by-ref coroutine if `ClosureKind::Fn | ClosureKind::FnMut`, and the by-move coroutine if `ClosureKind::FnOnce`.
 
-## Trait Hierarchy
+### Trait Hierarchy
 
 We introduce a parallel hierarchy of `Fn*` traits that are implemented for . The motivation for the introduction was covered in a blog post: [Async Closures](https://hackmd.io/@compiler-errors/async-closures).
 
@@ -98,7 +102,7 @@ We mention above that "regular" callable types can implement `AsyncFn*`, but the
 
 See the "follow-up: when do..." section below for an elaborated answer. The full answer describes a pretty interesting and hopefully thorough heuristic that is used to ensure that most async closures "just work".
 
-## Tale of two bodies...
+### Tale of two bodies...
 
 When async closures are called with `AsyncFn`/`AsyncFnMut`, they return a coroutine that borrows from the closure. However, when they are called via `AsyncFnOnce`, we consume that closure, and cannot return a coroutine that borrows from data that is now dropped.
 
@@ -120,7 +124,7 @@ Since we've synthesized a new def id, this query is also responsible for feeding
 
 [^b3]: <https://github.com/rust-lang/rust/blob/5ca0e9fa9b2f92b463a0a2b0b34315e09c0b7236/compiler/rustc_mir_transform/src/lib.rs#L339-L342>
 
-## Closure signature inference
+### Closure signature inference
 
 The closure signature inference algorithm for async closures is a bit more complicated than the inference algorithm for "traditional" closures. Like closures, we iterate through all of the clauses that may be relevant (for the expectation type passed in)[^deduce1].
 
@@ -173,7 +177,7 @@ s.as_bytes();
 
 So *instead*, we use this alias (in this case, a projection: `AsyncFnKindHelper::Upvars<'env, ...>`) to delay the computation of the *tupled upvars* and give us something to put in its place, while still allowing us to return a `TyKind::Coroutine` (which is a rigid type) and we may successfully confirm the built-in traits we need (in our case, `Future`), since the `Future` implementation doesn't depend on the upvars at all.
 
-## Upvar analysis
+### Upvar analysis
 
 By and large, the upvar analysis for coroutine-closures and their child coroutines proceeds like normal upvar analysis. However, there are several interesting bits that happen to account for async closures' special natures:
 
@@ -262,7 +266,7 @@ let c = async || {
 
 If either of these cases apply, then we should capture the borrow with the lifetime of the parent coroutine-closure's env. Luckily, if this function is not correct, then the program is not unsound, since we still borrowck and validate the choices made from this function -- the only side-effect is that the user may receive unnecessary borrowck errors.
 
-## Instance resolution
+### Instance resolution
 
 If a coroutine-closure has a closure-kind of `FnOnce`, then its `AsyncFnOnce::call_once` and `FnOnce::call_once` implementations resolve to the coroutine-closure's body[^res1], and the `Future::poll` of the coroutine that gets returned resolves to the body of the child closure.
 
@@ -282,7 +286,7 @@ This is represented by the `ConstructCoroutineInClosureShim`[^i1]. The `receiver
 
 [^i3]: <https://github.com/rust-lang/rust/blob/07cbbdd69363da97075650e9be24b78af0bcdd23/compiler/rustc_middle/src/ty/instance.rs#L841>
 
-## Borrow-checking
+### Borrow-checking
 
 It turns out that borrow-checking async closures is pretty straightforward. After adding a new `DefiningTy::CoroutineClosure`[^bck1] variant, and teaching borrowck how to generate the signature of the coroutine-closure[^bck2], borrowck proceeds totally fine.