|
| 1 | +//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why |
| 2 | +//! it is necessary. |
| 3 | +//! |
| 4 | +//! This code does not cause an immediate normalization error in typeck, because we |
| 5 | +//! don't reveal the hidden type returned by `opaque<T>` in the analysis typing mode. |
| 6 | +//! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know |
| 7 | +//! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound, |
| 8 | +//! but cannot normalize `<{opaque} as Project2>::Assoc2` any further. |
| 9 | +//! |
| 10 | +//! However, in the post-analysis typing mode, which is used for the layout computation, |
| 11 | +//! the opaque's hidden type is revealed to be `PhantomData<T>`, and now we fail to |
| 12 | +//! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound |
| 13 | +//! in the param env! This happens, because `PhantomData<T>: Project2` only holds if |
| 14 | +//! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the |
| 15 | +//! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not |
| 16 | +//! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead. |
| 17 | +//! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing |
| 18 | +//! `<PhantomData<T> as Project2>::Assoc2` fails. |
| 19 | +//! |
| 20 | +//! Note that this layout error can only happen when computing the layout in a generic |
| 21 | +//! context, which is not required for codegen, but may happen for lints, MIR optimizations, |
| 22 | +//! and the transmute check. |
| 23 | +
|
| 24 | +use std::marker::PhantomData; |
| 25 | + |
| 26 | +trait Project1 { |
| 27 | + type Assoc1; |
| 28 | +} |
| 29 | + |
| 30 | +impl<T> Project1 for T { |
| 31 | + type Assoc1 = (); |
| 32 | +} |
| 33 | + |
| 34 | +trait Project2 { |
| 35 | + type Assoc2; |
| 36 | + fn get(self) -> Self::Assoc2; |
| 37 | +} |
| 38 | + |
| 39 | +impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> { |
| 40 | + type Assoc2 = (); |
| 41 | + fn get(self) -> Self::Assoc2 {} |
| 42 | +} |
| 43 | + |
| 44 | +fn opaque<T>() -> impl Project2 { |
| 45 | + PhantomData::<T> |
| 46 | +} |
| 47 | + |
| 48 | +fn check<T: Project1>() { |
| 49 | + unsafe { |
| 50 | + std::mem::transmute::<_, ()>(opaque::<T>().get()); |
| 51 | + //~^ ERROR: cannot transmute |
| 52 | + //~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized) |
| 53 | + //~| NOTE: (0 bits) |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +fn main() {} |
0 commit comments