---
# System prepended metadata

title: Opaque types in new solver

---

## 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!
}
```


