Fix subst issues with return-position impl Trait in trait by compiler-errors · Pull Request #102334 · rust-lang/rust (original) (raw)

@cjgillot:

I'm not really sure what you mean by this. The inferred opaque type shouldn't have any late-bound regions -- associated types don't have late-bound regions, do they?

I guess an example might help explain my thinking in this change -- let's look at a manual desugaring of an RPITIT:

RPITIT:

trait Foo { fn foo<'a>(&'a self) -> impl Display + 'a; }

struct Wrapper(T);

impl<T: Display> Foo for Wrapper { fn foo<'a>(&'a self) -> impl Display + 'a { &self.0 } }

GAT:

trait Foo { type FooRpit<'a>: Display + 'a;

fn foo<'a>(&'a self) -> &'a T; }

struct Wrapper(T);

impl Foo for Wrapper { type FooRpit<'a> = &'a i32;

fn foo<'a>(&'a self) -> Self::FooRpit<'a> { &self.0 } }

In the GAT example, when we're projecting <Wrapper<i32> as Foo>::FooRpit<'_#0r> (substs = [Wrapper<i32>, '_#0r]), we first infer that the {impl#0} provides the asociated type. That impl itself is inferred to have the substs [], and the {impl#0}::FooRpit unsubstituted type value is &'a/0 i32, where 'a/0 is an early-bound region with index 0 in the substs list. We rebase the substs above onto the impl substs to get ['_#0r], substitute to get &'_#0r i32.

However, in the RPITIT example {impl#0}::FooRpit isn't actually a real item, so during the RPIT inference step, we need to "renumber" the opaque type's early-bound lifetimes (taken from the opaque item in the trait) counting up from the impl's own substs as if a corresponding associated item existed, so we can later substitute things correctly during projection. Since the impl has no substs of its own, the early bound regions of FooRpit start counting from zero, not one.

If we don't do this, then the type_of value of the corresponding RPITIT to {impl#0}::FooRpit would be &'a/1 i32 (since 'a/1 comes from the trait, which has a Self subst in the 0th position), which would be out of bounds considering the rebased impl substs I mentioned above.

the corresponding lifetime in the impl is late-bound, and we should build the correct binder

If we wrapped things in binders instead, then I think we'd be treating the function foo in the impl like for<'a> fn(&'a self) -> for<'b> &'b i32 even though the lifetime of &self and &i32 in that above example should be related through substs.