Fix subst issues with return-position impl Trait
in trait by compiler-errors · Pull Request #102334 · rust-lang/rust (original) (raw)
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.