---
# System prepended metadata

title: impl Trait implementation plan

---

# impl Trait implementation plan

## Goals

* Stabilize what we can
* Have a plan to see things through 

## Slice 0

Goal:

* Enable people to have a traits that return iterators/futures, at least in some cases where GATs aren't needed

Proposal:

* permit impl Trait in type aliases and associated types
    * even if the `impl Trait` is not used directly but as a field of an aggregate, e.g. `(&str, impl Trait)` or `Foo<impl Trait>`
* forbid type alises containing impl Trait from appearing outside of "return position"
* remove the hack that prevents cycles errors when an associated type would be normalized to an opaque type

```rust
// OK, because Foo is used in Return Position
type Foo = impl Trait;
fn foo() -> Foo {
}

// OK, because `Self::Iter` (in the trait)
// is only used in return position?
impl IntoIterator for MyType {
    type IntoIter = impl Iterator<Item = ...>;
    type Item = u32;

    fn into_iter(self) -> Self::IntoIter {
        let x: Self::Iter = ...;
        ///    ^^^^^^^^^^ would get a cycle error from normalization
        let y: <MyType as IntoIterator>::IntoIter;
        // what about 
        
    }
}
```

Things to test:

* in argument position (should be disallowed)


## Slice 1

* Mingling the opaque + "under inference" type within a fn body
    * Technically possible today due to recursion, if you are careful, but harder to observe

```rust
// Interesting example 1: If we replaced `Foo` with an
// inference variable here, as proposed by RFC, then
// the method dispatch would error. This is "odd" since
// the method dispatch would work ok if `foo` were not in
// the defining scope, but maybe ultimately acceptable?
type Foo = impl Method;
fn foo(x: Foo) {
    x.method(); // will give errors
}

// Replacing with inference variables and recursion shows
// this "normalizing" has to be done through type-checking:
type Foo = impl Method;
type Bar = impl Method;

fn foo(count: usize) -> Foo {
    let x: usize = bar(); // return type of `foo` has to be changed
    22_usize
}

fn bar() -> Bar {
    // is this legal? probably not, as it only partially constrains Foo and Bar.
    foo()
}
```

## What traits should an opaque type implement?

```rust
fn foo() {
    let a: impl Display = 22;
    // Per RFC, I don't know that `typeof(x): Debug`
}

type Foo = impl Display;
fn foo() {
    let b: Foo = 22_usize;
    // I do know that `typeof(x): Debug`? Not very clear.

    let c: usize = x;
    // But we can accept this?
}
```

## What currently happens

* replace opaque type with inference variable in return position
* in other positions, it remains opaque
* we don't error if it's a type-alias impl trait

```rust
type Foo = impl Trait;
fn foo1() -> Foo { // hence Foo = opaque type is inferred here
    foo2() // has the opaque type
}
fn foo2() -> Foo {
    222
}
```


compiles today:

[playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=8a9a4c8c765a7917af0c3211208392e2)

```rust
#![feature(type_alias_impl_trait)]

struct MyType { }

impl IntoIterator for MyType {
    type IntoIter = impl Iterator<Item = u32>;
    type Item = u32;
    
    fn into_iter(self) -> Self::IntoIter {
        if false {
            // normalizes because of some hack that prevents the
            // cycle hack. If you don't use `panic!` but rather `vec![22].into_iter()`, you get a type error
            // here because `Self::IntoIter` is normalized
            // to the opaque type
            let x: Self::IntoIter = panic!();
        }
        vec![22].into_iter()
    }
}
```

## Expected semantics?

```rust
fn foo(x: impl Debug) {}
```

`x`'s type is opaque.

```rust
#![feature(type_alias_impl_trait)]
type Foo = (&'static str, impl std::fmt::Debug);

fn foo() -> Foo {
    ("foo", 42)
}
```

works

```rust
#![feature(type_alias_impl_trait)]
type Foo = impl std::fmt::Debug;

fn foo() -> Foo {
    "foo"
}
```
