6

Stabilize `impl_trait_projections` by compiler-errors 路 Pull Request #115659 路 r...

 11 months ago
source link: https://github.com/rust-lang/rust/pull/115659
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Member

Closes #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:

#![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 has a small section about why this is necessary -- this was written for RPITITs, but it applies to all RPITs)

Prior to #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 (#61949 (comment)) (#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 #62849 to deny this subtle behavior as a known limitation of the compiler. It was attempted by @cjgillot to fix this in #91403, which was subsequently unlanded. Then it was re-attempted to much success (馃帀) in #103491, which is where we currently are in the compiler.

The PR above (#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.

dtolnay, kekeimiku, vincenzopalazzo, c410-f3r, est31, and A248 reacted with thumbs up emojiDirbaio, bugadani, lqd, cjgillot, c410-f3r, kekeimiku, 9names, jaudiger, y21, Ragarnoy, and 8 more reacted with hooray emoji

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK