//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why //! it is necessary. //! //! This code does not cause an immediate normalization error in typeck, because we //! don't reveal the hidden type returned by `opaque` in the analysis typing mode. //! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know //! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound, //! but cannot normalize `<{opaque} as Project2>::Assoc2` any further. //! //! However, in the post-analysis typing mode, which is used for the layout computation, //! the opaque's hidden type is revealed to be `PhantomData`, and now we fail to //! normalize ` as Project2>::Assoc2` if there is a `T: Project1` bound //! in the param env! This happens, because `PhantomData: Project2` only holds if //! `::Assoc1 == ()` holds. This would usually be satisfied by the //! blanket `impl Project1 for T`, but due to the `T: Project1` bound we do not //! normalize `::Assoc1` via the impl and treat it as rigid instead. //! Therefore, `PhantomData: Project2` does NOT hold and normalizing //! ` as Project2>::Assoc2` fails. //! //! Note that this layout error can only happen when computing the layout in a generic //! context, which is not required for codegen, but may happen for lints, MIR optimizations, //! and the transmute check. use std::marker::PhantomData; trait Project1 { type Assoc1; } impl Project1 for T { type Assoc1 = (); } trait Project2 { type Assoc2; fn get(self) -> Self::Assoc2; } impl> Project2 for PhantomData { type Assoc2 = (); fn get(self) -> Self::Assoc2 {} } fn opaque() -> impl Project2 { PhantomData:: } fn check() { unsafe { std::mem::transmute::<_, ()>(opaque::().get()); //~^ ERROR: cannot transmute //~| NOTE: (unable to determine layout for `::Assoc2` because `::Assoc2` cannot be normalized) //~| NOTE: (0 bits) } } fn main() {}