## Candidate selection can define opaques the following compiles defining `Op = u8`: ```rust #![feature(type_alias_impl_trait)] type Op = impl Sized; trait Trait {} impl Trait for Box<u8> {} fn impl_trait<T: Trait>() {} fn test() -> Option<Op> { impl_trait::<Box<Op>>; None } ``` another one: ```rust #![feature(type_alias_impl_trait)] trait Equate {} impl<T: Sized> Equate for (T, T) {} fn equate<X: Equate>() {} type Op = impl Sized; fn test(p: Op) { let _: u8 = p; equate::<(Op, u8)>; } ``` ## Selection is aware of hidden types We normalize the opaque to the hidden type during selection if we're in a defining scope. The following passes typeck but ICEs mir-typeck because we don't populate the hidden types from typeck in mir-typeck early enough. More specifically, `check_user_type_annnotations` is called before we register the hidden types. ```rust #![feature(type_alias_impl_trait)] type Op = impl Sized; trait Trait {} impl Trait for u16 {} impl Trait for u32 {} fn impl_trait<T: Trait>() {} fn test() -> Op { impl_trait::<Op>; 0u32 } ``` ## Normalize Self in a non-defining function This fails with an ambiguity rather than a hard error. With the goal `Op: Trait`, `Op` is normalized to a fresh inference variable because we're inside a defining scope for `Op` but the hidden type will never be constrained in the function body. ```rust #![feature(type_alias_impl_trait)] trait Trait {} impl Trait for () {} type Op = impl Sized; fn get() -> Op {} fn impl_trait<T: Trait>() {} fn test() -> Op { impl_trait::<Op>; //~^ ERROR type annotations needed: cannot satisfy `Op: Trait` get() } ``` ## Inference order-dependence Given `?0 = u8 && ?0 = impl Sized`, does `?0: Copy` hold? The old behviour is order-dependent. This is not an issue in the new solver but it would be if we were to remove the lazy normalization of opaques. ```rust #![feature(type_alias_impl_trait)] type Opaque = impl Sized; fn is_copy<T: Copy>(_: T, _: T) {} fn test(p: Opaque) { is_copy(p, 0u8); // FAIL! is_copy(0u8, p); // PASS! } ```