| //! 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<T>` 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<T>`, and now we fail to | |
| //! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound | |
| //! in the param env! This happens, because `PhantomData<T>: Project2` only holds if | |
| //! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the | |
| //! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not | |
| //! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead. | |
| //! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing | |
| //! `<PhantomData<T> 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<T> Project1 for T { | |
| type Assoc1 = (); | |
| } | |
| trait Project2 { | |
| type Assoc2; | |
| fn get(self) -> Self::Assoc2; | |
| } | |
| impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> { | |
| type Assoc2 = (); | |
| fn get(self) -> Self::Assoc2 {} | |
| } | |
| fn opaque<T>() -> impl Project2 { | |
| PhantomData::<T> | |
| } | |
| fn check<T: Project1>() { | |
| unsafe { | |
| std::mem::transmute::<_, ()>(opaque::<T>().get()); | |
| //~^ ERROR: cannot transmute | |
| //~| NOTE: source type: `{type error}` (the type has an unknown layout) | |
| //~| NOTE: target type: `()` (0 bits) | |
| } | |
| } | |
| fn main() {} |