# RPIT refactor
## 2022-09-14
https://gist.github.com/nikomatsakis/3ca370ae809cbee81b20a3e8ef504542
```rust
// Example B
use std::fmt::Debug;
trait SomeTrait<'b>: Debug { }
fn foo<'b, T>(t: T) -> impl Debug
where
T: SomeTrait<'b>
{
MyType { t }
}
struct MyType<T>
where
T: Debug,
{
x: T,
}
```
* `generics_of`
* TAIT that has `['b, T]`
* `predicates_of`
* read the predicates from the fn
* `[T: SomeTrait<'b>]`
* elaborate them
* `[T: SomeTrait<'b>, T: Debug]`
* map lifetimes we wish to keep to their new names
* (there are no lifetimes we wish to keep)
* filter out the ones that reference lifetimes we are not keeping
* `[T: Debug]`
issue: blanket impls
```rust
trait SomeTrait<'b> { }
trait Foo {}
impl<'a, T: SomeTrait<'a>> Foo for T {}
fn foo<'b, T>(t: T) -> impl Foo
where
T: SomeTrait<'b>
{
t
}
```
```rust
// Example A:
use std::fmt::Debug;
trait SomeTrait<'a>: Debug { }
fn foo<'a, T>(t: &'a T) -> impl Debug + 'a
where
T: SomeTrait<'a>
{
MyType { t }
}
struct MyType<'a, T>
where
T: SomeTrait<'a>,
{
x: &'a T,
}
```
Current handling:
* `generics_of(D) = ['a, T, 'a1]`
* `predicates_of(D) = []`
* and then we have this check later:
* `hidden_type(D) = &'a1 T`
* `predicates_of(F) = T: SomeTrait<'a>`
* prove that the hidden type is well-formed
* `WF(&'a1 T)` requires
* `T: SomeTrait<'a1>`
* this winds up requiring that `'a = 'a1`
* but we skip region error reporting
```rust
// Example C:
use std::fmt::Debug;
trait SomeTrait<'a>: Debug { }
fn foo<'a, 'b, T>(t: &'b T) -> impl Debug + 'b
where
T: SomeTrait<'a>,
T: ThirdTrait<'b>
{
MyType { t }
}
struct MyType<'b, T>
where
T: SomeOtherTrait,
T: ThirdTrait<'b>
{
x: &'b T,
}
trait OtherTrait { }
impl<'a, T> SomeOtherTrait for T
where
T: SomeTrait<'a>,
{ }
```
Maybe:
* `generics_of(D) = ['a, 'b, T, 'b1]`
* `predicates_of(D) = [T: SomeTrait<'a>, T: ThirdTrait<'b1>]`
* the wf checking works out
But then:
```
fn foo<'a, 'b>() -> Foo<'a, 'b, T, 'b>
```
## 2022-09-13
Niko is wondering about an alternate approach to the PR in which:
* we have a def-id for each `impl Trait` already
* we would create an `OpaqueType` definition for that def-id
* this opaque-type would link to the item in which the def-id appears
* e.g., the function (if it's an RPIT) or the type alias (if not)
* invoking `generics_of` on this opaque-type def-id
* could invoke `generics_of` on the function
* filter out the lifetimes to create a new `Generics<'tcx>`
* but that will cause a problem:
* `TyParam(index, ...)` in the `Ty<'tcx>`
* and that index counts from 0
* other things are in terms of the old index
can we make def-ids in astconv?
in place of existential lifetimes, can you use elaboration
```rust
trait SomeTrait<'a>: Debug { }
fn foo<'a, T>(t: T) -> impl Debug
where
T: SomeTrait<'a>
{
t
}
// we lower that in query layer
type Foo<T>: Debug // OpaqueTy
where
T: Debug; // we get this by elaborating
fn foo<'a, T>(t: T) -> Foo<T>
where
T: SomeTrait<'a>
{
t // could happen that 'a becomes 'static
}
```
Elaborate: `T: SomeTrait<'a>` which gives
`T: SomeTrait<'a>`
`T: Debug`
then we remove anything that mentions the existential lifetime `'a`
we're left with `T: Debug` and we are happy
## older
### `'static'` considerd bad
```rust
trait SomeTrait<'a>: Debug { }
fn foo<'a, T>(t: T) -> impl Debug
where
T: SomeTrait<'a>
{
t
}
// we lower that to
type Foo<T>: Debug // OpaqueTy
where
T: SomeTrait<'static>; // uh oh
fn foo<'a, T>(t: T) -> Foo<T>
where
T: SomeTrait<'a>
{
t // could happen that 'a becomes 'static
}
// example not real, ui tests have example
```
```
'a: 'b, but we only capture `'a`
so we get
'a: 'static
which means `'a` == `'static`
```
and then we can transmute random lifetimes or return references to local things from functions: BAD
### ignore where bounds
saw breakage on crater because bounds end up in ParamEnv and since we had no bounds, ParamEnv was empty, thus got an error that `I` does not implement `Iterator`, even though `I: Iterator` (because we did not register that bound).
add test in CI
does this trigger it?
```rust
fn foo<I: Iterator>(i: I) -> impl Iterator {
i
}
```
### invoke magic Niko
```rust
trait SomeTrait<'a>: Debug { }
fn foo<'a, T>(t: T) -> impl Debug
where
T: SomeTrait<'a>
{
t
}
// we lower that to
type Foo<T>: Debug // OpaqueTy
where
exists<'x> T: SomeTrait<'x>; // yay?
fn foo<'a, T>(t: T) -> Foo<T>
where
T: SomeTrait<'a>
{
t
}
```
problem: people are worse than fuzzers
```rust
trait Foo<'a, T>
where
T: Trait<'a>
{}
fn something<'a, T, U>() -> impl Sized
where
U: Foo<'a, T>,
T: Trait<'a>, // <-- required for `U: Foo` to be WF
we would desugar to
type Foo<T>: Sized // OpaqueTy
where
exists<'x> U: Foo<'x, T>;
exists<'x> T: Trait<'x>;
```
also
```rust
impl<'a, T> Bop for T
where
T: Foo<'a>
T: Bar<'a>
{}
fn something<'a, T>(t: T) -> impl Bop
where
U: Foo<'a>,
U: Bar<'a>,
{
t
}
```
ignore in first iteration, just implement exists bounds.
```rust
where exists<'a> T: Debug
```