rust-lang/rust · critical

discr subgoal...

Error message

discr subgoal...

What it means

consider_builtin_discriminant_kind_candidate (normalizes_to.rs:1009) computes `<T as DiscriminantKind>::Discriminant` for each type kind. The `ty::UnsafeBinder(_)` arm calls `unimplemented!("discr subgoal...")` — this is deliberately unfinished code (note the inline FIXME(unsafe_binders) comment) rather than an invariant guard. UnsafeBinder is an experimental, still-in-development type kind, and computing its discriminant has not been implemented yet, so the compiler aborts instead of guessing.

Source

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

            | ty::FnDef(..)
            | ty::FnPtr(..)
            | ty::Closure(..)
            | ty::CoroutineClosure(..)
            | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
            | ty::Coroutine(..)
            | ty::CoroutineWitness(..)
            | ty::Never
            | ty::Foreign(..)
            | ty::Adt(_, _)
            | ty::Str
            | ty::Slice(_)
            | ty::Dynamic(_, _)
            | ty::Tuple(_)
            | ty::Error(_) => self_ty.discriminant_ty(ecx.cx()),

            ty::UnsafeBinder(_) => {
                // FIXME(unsafe_binders): instantiate this with placeholders?? i guess??
                unimplemented!("discr subgoal...")
            }

            // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid
            // alias. In case there's a where-bound further constraining this alias it is preferred over
            // this impl candidate anyways. It's still a bit scuffed.
            ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) | ty::Placeholder(..) => {
                return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
                    ecx.instantiate_normalizes_to_as_rigid(goal)?;
                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                });
            }

            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
            | ty::Alias(ty::IsRigid::No, _)
            | ty::Bound(..) => panic!(
                "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
                goal.predicate.self_ty()
            ),

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Avoid using unsafe binder types in positions where a discriminant query is required until the feature is implemented.
  2. Update to the latest nightly and re-check; if still unimplemented, wait for the unsafe_binder feature to progress (track the FIXME/issue).
  3. Disable -Znext-solver so the legacy solver (which does not exercise this builtin path) is used.
  4. File an issue at https://github.com/rust-lang/rust/issues noting the unsafe_binder discriminant gap, referencing normalizes_to.rs:1009.

Example fix

// before: discriminant query on an unsafe binder type
unsafe_binder fn handle(b: unsafe binder T) {
    let _ = std::mem::discriminant(&b); // unimplemented discr subgoal
}

// after: move the value out of the unsafe binder before querying
unsafe_binder fn handle(b: unsafe binder T) {
    let v: T = unsafe { wrap(b) };
    let _ = std::mem::discriminant(&v);
}
Defensive patterns

Strategy: validation

Validate before calling

// Fires while solving a DiscriminantKind subgoal for an ill-formed self type.
// Constrain to a concrete, well-formed enum/struct before relying on discriminants.
#[repr(u8)] enum E { A, B, C }
fn discr_of(e: E) -> <E as core::marker::DiscriminantKind>::Discriminant { e as u8 as _ }

Type guard

// Restrict discriminant queries to concrete, sized, well-formed enums:
fn discr<T: Sized + 'static>() -> <T as core::marker::DiscriminantKind>::Discriminant { unimplemented!() }

Prevention

When it happens

Trigger: Code that uses unsafe binder types (the nightly `unsafe_binder` feature) and triggers a discriminant-kind query on such a type under -Znext-solver — e.g. mem::discriminant, match-equivalent checks, or any path requiring `<T as DiscriminantKind>::Discriminant` where T is an UnsafeBinder.

Common situations: Experimenting with the unstable `unsafe_binder` feature on a nightly that has the type kind but not its discriminant handling; a dependency that opts into unsafe_binder behind a feature flag; tracking the upstream RFC as it lands incrementally.

Related errors


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