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