{"id":"846744addd6bbc65","repo":"rust-lang/rust","slug":"unexpected-self-ty-when-normalizing-t-as","errorCode":null,"errorMessage":"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`","messagePattern":"unexpected self ty `(.+?)` when normalizing `<T as Pointee>::Metadata`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs","lineNumber":792,"sourceCode":"                ),\n            },\n            ty::Adt(_, _) => Ty::new_unit(cx),\n\n            ty::Tuple(elements) => match elements.last() {\n                None => Ty::new_unit(cx),\n                Some(tail_ty) => {\n                    Ty::new_projection(cx, ty::IsRigid::No, metadata_def_id, [tail_ty])\n                }\n            },\n\n            ty::UnsafeBinder(_) => {\n                // FIXME(unsafe_binder): Figure out how to handle pointee for unsafe binders.\n                unimplemented!()\n            }\n\n            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))\n            | ty::Alias(ty::IsRigid::No, _)\n            | ty::Bound(..) => panic!(\n                \"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`\",\n                goal.predicate.self_ty()\n            ),\n        };\n\n        ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {\n            ecx.instantiate_normalizes_to_term(goal, metadata_ty.into())?;\n            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)\n        })\n    }\n\n    fn consider_builtin_future_candidate(\n        ecx: &mut EvalCtxt<'_, D>,\n        goal: Goal<I, Self>,\n    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {\n        let self_ty = goal.predicate.self_ty();\n        let ty::Coroutine(def_id, args) = self_ty.kind() else {\n            return Err(NoSolution.into());","sourceCodeStart":774,"sourceCodeEnd":810,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs#L774-L810","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: <T as Pointee>::Metadata queried with T unconstrained\nfn meta<T>() {\n    let _: <T as std::pointee::Pointee>::Metadata;\n}\n\n// after: constrain T so metadata is statically known\nfn meta<T: Sized>() {\n    let _: <T as std::pointee::Pointee>::Metadata; // resolves to ()\n}","handlingStrategy":"validation","validationCode":"// Pointee::Metadata must be normalized against a fully concrete/inferred Self.\n// Materialize the type before projecting Metadata:\nuse core::ptr::Pointee;\ntype MetaOf<T> = <T as Pointee>::Metadata;       // OK when T is concrete\nfn check_str() { let _: MetaOf<str> = (); }      // str -> DynMetadata\n","typeGuard":"// Only allow projection when Self is Sized or a known `dyn Trait`/slice:\ntrait KnownPointee: Pointee {}\nimpl<T: Sized> KnownPointee for T {}\nimpl KnownPointee for str {}\nimpl KnownPointee for [u8] {}\nfn meta<T: KnownPointee>() -> <T as Pointee>::Metadata { unimplemented!() }\n","tryCatchPattern":null,"preventionTips":["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."],"tags":["rust","rustc","trait-solver","next-solver","ice","panic","pointee","metadata","inference","projection"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}