You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Auto merge of rust-lang#115659 - compiler-errors:itp, r=cjgillot
Stabilize `impl_trait_projections`
Closesrust-lang#115659
## TL;DR:
This allows us to mention `Self` and `T::Assoc` in async fn and return-position `impl Trait`, as you would expect you'd be able to.
Some examples:
```rust
#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
// (just needed for final tests below)
// ---------------------------------------- //
struct Wrapper<'a, T>(&'a T);
impl Wrapper<'_, ()> {
async fn async_fn() -> Self {
//^ Previously rejected because it returns `-> Self`, not `-> Wrapper<'_, ()>`.
Wrapper(&())
}
fn impl_trait() -> impl Iterator<Item = Self> {
//^ Previously rejected because it mentions `Self`, not `Wrapper<'_, ()>`.
std::iter::once(Wrapper(&()))
}
}
// ---------------------------------------- //
trait Trait<'a> {
type Assoc;
fn new() -> Self::Assoc;
}
impl Trait<'_> for () {
type Assoc = ();
fn new() {}
}
impl<'a, T: Trait<'a>> Wrapper<'a, T> {
async fn mk_assoc() -> T::Assoc {
//^ Previously rejected because `T::Assoc` doesn't mention `'a` in the HIR,
// but ends up resolving to `<T as Trait<'a>>::Assoc`, which does rely on `'a`.
// That's the important part -- the elided trait.
T::new()
}
fn a_few_assocs() -> impl Iterator<Item = T::Assoc> {
//^ Previously rejected for the same reason
[T::new(), T::new(), T::new()].into_iter()
}
}
// ---------------------------------------- //
trait InTrait {
async fn async_fn() -> Self;
fn impl_trait() -> impl Iterator<Item = Self>;
}
impl InTrait for &() {
async fn async_fn() -> Self { &() }
//^ Previously rejected just like inherent impls
fn impl_trait() -> impl Iterator<Item = Self> {
//^ Previously rejected just like inherent impls
[&()].into_iter()
}
}
```
## Technical:
Lifetimes in return-position `impl Trait` (and `async fn`) are duplicated as early-bound generics local to the opaque in order to make sure we are able to substitute any late-bound lifetimes from the function in the opaque's hidden type. (The [dev guide](https://rustc-dev-guide.rust-lang.org/return-position-impl-trait-in-trait.html#aside-opaque-lifetime-duplication) has a small section about why this is necessary -- this was written for RPITITs, but it applies to all RPITs)
Prior to rust-lang#103491, all of the early-bound lifetimes not local to the opaque were replaced with `'static` to avoid issues where relating opaques caused their *non-captured* lifetimes to be related. This `'static` replacement led to strange and possibly unsound behaviors (rust-lang#61949 (comment)) (rust-lang#53613) when referencing the `Self` type alias in an impl or indirectly referencing a lifetime parameter via a projection type (via a `T::Assoc` projection without an explicit trait), since lifetime resolution is performed on the HIR, when neither `T::Assoc`-style projections or `Self` in impls are expanded.
Therefore an error was implemented in rust-lang#62849 to deny this subtle behavior as a known limitation of the compiler. It was attempted by `@cjgillot` to fix this in rust-lang#91403, which was subsequently unlanded. Then it was re-attempted to much success (🎉) in rust-lang#103491, which is where we currently are in the compiler.
The PR above (rust-lang#103491) fixed this issue technically by *not* replacing the opaque's parent lifetimes with `'static`, but instead using variance to properly track which lifetimes are captured and are not. The PR gated any of the "side-effects" of the PR behind a feature gate (`impl_trait_projections`) presumably to avoid having to involve T-lang or T-types in the PR as well. `@cjgillot` can clarify this if I'm misunderstanding what their intention was with the feature gate.
Since we're not replacing (possibly *invariant*!) lifetimes with `'static` anymore, there are no more soundness concerns here. Therefore, this PR removes the feature gate.
Tests:
* `tests/ui/async-await/feature-self-return-type.rs`
* `tests/ui/impl-trait/feature-self-return-type.rs`
* `tests/ui/async-await/issues/issue-78600.rs`
* `tests/ui/impl-trait/capture-lifetime-not-in-hir.rs`
---
r? cjgillot on the impl (not much, just removing the feature gate)
I'm gonna mark this as FCP for T-lang and T-types.
0 commit comments