rust-lang/rust · critical
unexpected self ty `{:?}` when normalizing `<T as Pointee>::
Error message
unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata` What it means
consider_builtin_pointee_candidate (normalizes_to.rs:792) computes the concrete `<T as Pointee>::Metadata` type by matching on self_ty.kind(). Most arms produce a real metadata type (e.g. unit for Sized types, usize for slices/str). The final arm panics for Infer(TyVar|Fresh*), non-rigid Alias (an un-normalized projection), and Bound types. The invariant is that by the time a Pointee projection is evaluated, the self type must be concrete or at least a rigid alias / param / placeholder (which are handled earlier and return early); an unresolved inference variable, a still-normalizing alias, or a bound type should never reach this point.
Source
Thrown at compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs:792
),
},
ty::Adt(_, _) => Ty::new_unit(cx),
ty::Tuple(elements) => match elements.last() {
None => Ty::new_unit(cx),
Some(tail_ty) => {
Ty::new_projection(cx, ty::IsRigid::No, metadata_def_id, [tail_ty])
}
},
ty::UnsafeBinder(_) => {
// FIXME(unsafe_binder): Figure out how to handle pointee for unsafe binders.
unimplemented!()
}
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 Pointee>::Metadata`",
goal.predicate.self_ty()
),
};
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
ecx.instantiate_normalizes_to_term(goal, metadata_ty.into())?;
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
let self_ty = goal.predicate.self_ty();
let ty::Coroutine(def_id, args) = self_ty.kind() else {
return Err(NoSolution.into());View on GitHub (pinned to 22057b88b0)
Solutions
- Add a bound or annotation that makes the self type concrete before metadata is queried, e.g. constrain T: Sized (Metadata = ()) or specify the metadata type explicitly.
- Update to the latest nightly; goal-ordering bugs in the next solver's normalization pipeline are fixed frequently.
- Disable -Znext-solver to use the legacy solver's metadata handling.
- File an ICE with the self_ty value from the panic message and a minimal reproducer involving ptr::from_raw_parts / DynMetadata.
Example fix
// before: <T as Pointee>::Metadata queried with T unconstrained
fn meta<T>() {
let _: <T as std::pointee::Pointee>::Metadata;
}
// after: constrain T so metadata is statically known
fn meta<T: Sized>() {
let _: <T as std::pointee::Pointee>::Metadata; // resolves to ()
} Defensive patterns
Strategy: validation
Validate before calling
// Pointee::Metadata must be normalized against a fully concrete/inferred Self.
// Materialize the type before projecting Metadata:
use core::ptr::Pointee;
type MetaOf<T> = <T as Pointee>::Metadata; // OK when T is concrete
fn check_str() { let _: MetaOf<str> = (); } // str -> DynMetadata
Type guard
// Only allow projection when Self is Sized or a known `dyn Trait`/slice:
trait KnownPointee: Pointee {}
impl<T: Sized> KnownPointee for T {}
impl KnownPointee for str {}
impl KnownPointee for [u8] {}
fn meta<T: KnownPointee>() -> <T as Pointee>::Metadata { unimplemented!() }
Prevention
- Don't project `<T as Pointee>::Metadata` from a generic `T` that might be an inference variable or opaque.
- Constrain `T: Sized` (Metadata == `()`) or pin it to `str`/`[U]`/`dyn Trait` before projection.
- Prefer `core::ptr::DynMetadata<dyn Trait>` over hand-rolled Pointee normalization.
When it happens
Trigger: Code that forces `<T as Pointee>::Metadata` while T is still an unconstrained inference variable, a non-rigid projection that has not finished normalizing, or a bound type — e.g. std::ptr::from_raw_parts or DynMetadata usage on a fully generic T with no Sized/known-metadata bound, under -Znext-solver where an earlier normalization step failed to run or was reordered.
Common situations: Writing generic pointer-metadata helpers over `T` without bounding T; a next-solver goal-ordering regression that skips normalization of a projection before querying its metadata; nightly-only pointer-metadata or unsized-locals experimentation.
Related errors
- unexpected self ty `{:?}` when normalizing `<T as Discrimina
- 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:?}`
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/846744addd6bbc65.json.
Report an issue: GitHub.