rust-lang/rust · error

coroutine lowered from async fn should be in fn

Error message

coroutine lowered from async fn should be in fn

What it means

region_name.rs:841: when naming a region for an async-fn coroutine with CoroutineSource::Fn, the diagnostic looks up the parent item and calls parent_item.fn_decl().expect("coroutine lowered from async fn should be in fn"). The invariant: a coroutine desugared from an `async fn` is always nested inside an fn item, so the parent must have a fn_decl.

Source

Thrown at compiler/rustc_borrowck/src/diagnostics/region_name.rs:841

                    )) => " of async block",

                    hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                        hir::CoroutineDesugaring::Async,
                        hir::CoroutineSource::Closure,
                    ))
                    | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
                        " of async closure"
                    }

                    hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                        hir::CoroutineDesugaring::Async,
                        hir::CoroutineSource::Fn,
                    )) => {
                        let parent_item =
                            tcx.hir_node_by_def_id(tcx.hir_get_parent_item(mir_hir_id).def_id);
                        let output = &parent_item
                            .fn_decl()
                            .expect("coroutine lowered from async fn should be in fn")
                            .output;
                        span = output.span();
                        if let hir::FnRetTy::Return(ret) = output {
                            hir_ty = Some(self.get_future_inner_return_ty(ret));
                        }
                        " of async function"
                    }

                    hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                        hir::CoroutineDesugaring::Gen,
                        hir::CoroutineSource::Block,
                    )) => " of gen block",

                    hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                        hir::CoroutineDesugaring::Gen,
                        hir::CoroutineSource::Closure,
                    ))
                    | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. File a rustc ICE with the minimized async fn lifetime error.
  2. Restructure the async fn (move the problematic borrow out, name the lifetime explicitly) so the region-naming heuristic is not reached.
  3. Bisect across nightlies with cargo bisect-rustc.
  4. Try the equivalent non-async code to confirm the async-specific lowering path.
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: Region-naming for a borrowck error inside an async fn where the parent item is not an fn (has no fn_decl), an inconsistency in coroutine lowering or HIR parent tracking.

Common situations: A borrowck diagnostic ICE triggered by lifetime errors inside async fn on a nightly with a coroutine-lowering regression.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/9bebdd32fd83deff. Report an issue: GitHub.