Where RPIT is allowed:
fn f() -> impl Trait { /* ... body returning a single type ... */ }
The function writer chooses the concrete type returned, as opposed to generics/APIT, where the caller of the function can choose any type that meets the bounds. That's the point of RPIT, so there's no changing that.
Examples of where RPIT is parameterized by the input types are:
fn g<T: TraitOne>(t: T) -> impl TraitTwo {
// returned type may depend on T
// (but is otherwise concrete)
}
fn h(input: &str) -> impl Trait + '_ {
// returned type may depend on lifetime of input
// (but is otherwise concrete)
}
So then the question becomes, is it possible for "RPIT in APIT" to work like APIT? It seems very reasonable / straightforward for this example, but when you look at a parameterized case:
fn example(f: impl Fn(&str) -> impl Trait + '_) { /* ... */ }
This won't work:
fn example<F, R>(f: F)
where
F: Fn(&str) -> R,
R: Trait,
Because a type parameter like R
can only represent a single type, where as the return type varies over lifetimes.
So you need something like
// pseudo-code
fn example<F>(f: F)
where
F: Fn(&str) -> R<'_>,
for<'any> R<'any>: Trait,
Where that R<'_>
is a generic type constructor (which Rust doesn't have).
Or, for this particular case, you could have
// Using `Fn` traits in this form requires nightly features
fn example<F>(f: F)
where
for<'any> F: Fn<(&'any str,)>,
for<'any> <F as Fn<(&'any str,)>>::Output: Trait,
And you can emulate this on stable too with enough elbow grease... but
- It tends to wreck inference
- Rust currently can't deal with binders "changing levels" very well, like going from an inherently higher-ranked type
fn(&str) -> SomeType<'_>
to reasoning about a higher-ranked trait bound such as for<'any> <F as...>::Output: Bound
where the higher-rank binder is "outside" the type
So can it happen? I think something that works like the last example can happen some day, but it's probably complicated to implement, and in my experience definitely needs a more sophisticated compiler in terms of higher-ranked bounds checking and inference.
If they allowed simple cases now, it might paint them into a corner with regards to how the fully general case is implemented.