rust-lang/rust · critical
Coroutine is not const
Error message
Coroutine is not const
What it means
Internal `unreachable!` in the next-gen trait solver's const-effect assembly for the built-in `Coroutine` trait (`core::ops::Coroutine`). `consider_builtin_coroutine_candidate` is a stub because coroutines are not const-evaluable; reaching it means a `T: const Coroutine` host-effect goal was routed to built-in candidate assembly. The result is an ICE, not a graceful error.
Source
Thrown at compiler/rustc_next_trait_solver/src/solve/effect_goals.rs:406
fn consider_builtin_fused_iterator_candidate(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
unreachable!("FusedIterator is not const")
}
fn consider_builtin_async_iterator_candidate(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
unreachable!("AsyncIterator is not const")
}
fn consider_builtin_coroutine_candidate(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
unreachable!("Coroutine is not const")
}
fn consider_builtin_discriminant_kind_candidate(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
unreachable!("DiscriminantKind is not const")
}
fn consider_builtin_destruct_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
let cx = ecx.cx();
let self_ty = goal.predicate.self_ty();
let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?;
View on GitHub (pinned to 22057b88b0)
Solutions
- Drop the `const`/`~const Coroutine` bound — coroutines have no const impl.
- Check that no `#[const_trait]` trait lists `Coroutine` as a supertrait, which would synthesize the bound implicitly.
- Bisect nightlies and report the ICE upstream with a minimal reproducer using `-Znext-solver`.
- Retry with the classic solver to confirm the panic is isolated to the next solver's effect-goal path.
Example fix
// before
const fn step<G: const Coroutine>(_: G) {}
// after
fn step<G: Coroutine>(_: G) {} Defensive patterns
Strategy: validation
Validate before calling
// build.rs: reject const usage of coroutines (state machines)
fn main() {
let src = std::fs::read_to_string("src/lib.rs").unwrap_or_default();
for banned in ["~const Coroutine", "const Coroutine", "std::ops::Coroutine"] {
assert!(!src.contains(banned), "rejected: {banned} — Coroutine is a runtime state machine, not const");
}
println!("cargo:rerun-if-changed=src/lib.rs");
} Prevention
- Coroutines are resume-able state machines needing storage across suspensions; they cannot be const — keep `|...| yield ...` / `resume()` out of `const fn`.
- Do not put `~const Coroutine` bounds on generic const code.
- Replace coroutine logic in const contexts with plain pure functions and explicit state structs.
- If the panic appears without an explicit coroutine bound, it is a solver routing bug — reduce the reproducer and report upstream.
When it happens
Trigger: A host-effect goal resolves to the `Coroutine` lang item: a bound like `T: const Coroutine`, `T: ~const Coroutine`, or a coroutine/closure type being required to satisfy a const coroutine bound inside `const fn` or `#[const_trait]` code. Also reachable through opaque-type projection that hides a coroutine behind a const bound.
Common situations: Using nightly `coroutines`/`gen` feature together with `const_trait_impl`; writing `const fn` that generic-dispatches over a coroutine; `-Znext-solver` enabled on code with `yield`/`async gen` blocks; toolchain regression after coroutine effect-goal routing was added.
Related errors
- FusedIterator is not const
- AsyncIterator is not const
- DiscriminantKind is not const
- TransmuteFrom is not const
- BikeshedGuaranteedNoDrop is not const
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/d59f02b2bc243e47.json.
Report an issue: GitHub.