rust-lang/rust · critical

unexpected associated item `{:?}` for `{self_ty:?}`

Error message

unexpected associated item `{:?}` for `{self_ty:?}`

What it means

consider_builtin_coroutine_candidate (normalizes_to.rs:947) handles projections for the Coroutine trait, which has exactly two associated types: CoroutineReturn and CoroutineYield (checked via is_projection_lang_item). The else arm at line 947 panics if the projection's def_id is neither — an invariant that the only well-formed coroutine projections are those two. It can only fire if the lang-item set contains a third coroutine projection that this match was not updated to recognize.

Source

Thrown at compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs:947

            return Err(NoSolution.into());
        };

        // `async`-desugared coroutines do not implement the coroutine trait
        let cx = ecx.cx();
        if !cx.is_general_coroutine(def_id) {
            return Err(NoSolution.into());
        }

        let coroutine = args.as_coroutine();
        let def_id = goal.predicate.alias.expect_projection_ty_def_id();

        let term = if cx.is_projection_lang_item(def_id, SolverProjectionLangItem::CoroutineReturn)
        {
            coroutine.return_ty().into()
        } else if cx.is_projection_lang_item(def_id, SolverProjectionLangItem::CoroutineYield) {
            coroutine.yield_ty().into()
        } else {
            panic!("unexpected associated item `{:?}` for `{self_ty:?}`", def_id)
        };

        Self::probe_and_consider_implied_clause(
            ecx,
            CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
            goal,
            ty::ProjectionPredicate {
                projection_term: ty::AliasTerm::new(
                    ecx.cx(),
                    goal.predicate.alias.kind,
                    [self_ty, coroutine.resume_ty()],
                ),
                term,
            }
            .upcast(cx),
            // Technically, we need to check that the coroutine type is Sized,
            // but that's already proven by the coroutine being WF.
            [],

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Update to the latest nightly (rustup update nightly).
  2. Disable -Znext-solver to fall back to the legacy solver.
  3. File an ICE with the def_id and self_ty from the panic and a minimal reproducer (preferably using std::ops::Coroutine).
  4. Avoid manually projecting coroutine associated types on the affected nightly; rely on generator/async desugaring instead.
Defensive patterns

Strategy: validation

Validate before calling

// Generic catch-all for an associated item that doesn't exist on Self.
// Validate the item exists in the trait defn BEFORE projection:
trait Repo { fn get(&self, k: &str) -> u32; }   // only `get` exists
fn use_repo<R: Repo>(r: &R) { let _ = r.get("x"); } // OK

Type guard

// Compile-time check that the projected item name matches the trait declaration:
const _: fn() = || {
    fn _check<R: Repo>(_: &R) {}
};

Prevention

When it happens

Trigger: A NormalizesTo goal for a Coroutine projection whose def_id is neither CoroutineReturn nor CoroutineYield reaches the builtin-coroutine candidate path, under -Znext-solver. Requires a rustc internal where a new coroutine associated item exists but this arm predates it, or goal construction produced a malformed projection.

Common situations: Using coroutines/generators (nightly `gen`, `coroutine` trait) on a bleeding-edge nightly with -Znext-solver; a toolchain regression during rustc coroutine-trait refactoring; not triggered by typical async/await (which uses the Future path, not Coroutine's own assoc types).

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/4a7e7f909edf3444.json. Report an issue: GitHub.