rust-lang/rust · error

`async gen` closures not supported yet

Error message

`async gen` closures not supported yet

What it means

An `unimplemented!("\`async gen\` closures not supported yet")` ICE in `rustc_hir_typeck`'s closure type-checker. The `CoroutineClosure` desugaring handles `Gen` (gen closures) and `Async` (async closures), but the `AsyncGen` combination (async-gen closures) is recognized but not yet implemented and panics at closure.rs:197.

Source

Thrown at compiler/rustc_hir_typeck/src/closure.rs:197

                (
                    Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args),
                    Some(CoroutineTypes { resume_ty, yield_ty }),
                )
            }
            hir::ClosureKind::CoroutineClosure(kind) => {
                let (bound_return_ty, bound_yield_ty) = match kind {
                    hir::CoroutineDesugaring::Gen => {
                        // `iter!` closures always return unit and yield the `Iterator::Item` type
                        // that we have to infer.
                        (tcx.types.unit, self.infcx.next_ty_var(expr_span))
                    }
                    hir::CoroutineDesugaring::Async => {
                        // async closures always return the type ascribed after the `->` (if present),
                        // and yield `()`.
                        (bound_sig.skip_binder().output(), tcx.types.unit)
                    }
                    hir::CoroutineDesugaring::AsyncGen => {
                        unimplemented!("`async gen` closures not supported yet")
                    }
                };
                // Compute all of the variables that will be used to populate the coroutine.
                let resume_ty = self.next_ty_var(expr_span);

                let closure_kind_ty = match expected_kind {
                    Some(kind) => Ty::from_closure_kind(tcx, kind),

                    // Create a type variable (for now) to represent the closure kind.
                    // It will be unified during the upvar inference phase (`upvar.rs`)
                    None => self.next_ty_var(expr_span),
                };

                let coroutine_captures_by_ref_ty = self.next_ty_var(expr_span);
                let closure_args = ty::CoroutineClosureArgs::new(
                    tcx,
                    ty::CoroutineClosureArgsParts {
                        parent_args,

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Do not combine `async` and `gen` in the same closure; use a plain `async` block or a `gen` block separately.
  2. Express the pattern as an `async fn` returning a `gen` block (or vice-versa) instead of a single async-gen closure.
  3. Wait for / upgrade to a nightly where `AsyncGen` closures are implemented.

Example fix

// before (async gen closure -> ICE)
let c = async || { yield 1; };

// after — separate async and gen
async fn f() {
    let _g = gen { yield 1; };
}
Defensive patterns

Strategy: validation

Validate before calling

# Detect async+gen closure combinations
rg -nE 'async \|\|.*yield|gen move \|\|.*await' src/  # review matches

Prevention

When it happens

Trigger: Writing a closure that combines async and gen desugaring (an `async gen` closure) — e.g. an `async || { yield ... }` form — on a nightly toolchain where the coroutine-closure syntax is parsed but `AsyncGen` lowering is unfinished.

Common situations: Experimenting with the newest coroutine-closure features (`gen` + `async` combined) on nightly before the implementation lands. The parser accepts it; the type-checker does not.

Related errors


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