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
- Avoid using unsafe binder types in positions where a discriminant query is required until the feature is implemented.
- Update to the latest nightly and re-check; if still unimplemented, wait for the unsafe_binder feature to progress (track the FIXME/issue).
- Disable -Znext-solver so the legacy solver (which does not exercise this builtin path) is used.
- 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
- Avoid projecting `Discriminant` off generic inference variables or unsized types.
- Annotate enums with `#[repr(...)]` so the discriminant type is fully determined.
- Don't combine `DiscriminantKind` projection with auto-trait/`?Sized` puzzles in generic crates.
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
- no such associated type in `AsyncFn*`: {:?}
- `Tuple` does not have an associated type: {:?}
- `FusedIterator` does not have an associated type: {:?}
- unexpected associated item `{:?}` for `{self_ty:?}`
- `Unsize` does not have an associated type: {:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/df2b9d0cb4121fa4.json.
Report an issue: GitHub.