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