rust/compiler/rustc_typeck
bors 9d39f6ab7d Auto merge of #89970 - jackh726:gats_diagnostics, r=nikomatsakis
Implementation of GATs outlives lint

See #87479 for background. Closes #87479

The basic premise of this lint/error is to require the user to write where clauses on a GAT when those bounds can be implied or proven from any function on the trait returning that GAT.

## Intuitive Explanation (Attempt) ##
Let's take this trait definition as an example:
```rust
trait Iterable {
    type Item<'x>;
    fn iter<'a>(&'a self) -> Self::Item<'a>;
}
```
Let's focus on the `iter` function. The first thing to realize is that we know that `Self: 'a` because of `&'a self`. If an impl wants `Self::Item` to contain any data with references, then those references must be derived from `&'a self`. Thus, they must live only as long as `'a`. Furthermore, because of the `Self: 'a` implied bound, they must live only as long as `Self`. Since it's `'a` is used in place of `'x`, it is reasonable to assume that any value of `Self::Item<'x>`, and thus `'x`, will only be able to live as long as `Self`. Therefore, we require this bound on `Item` in the trait.

As another example:
```rust
trait Deserializer<T> {
    type Out<'x>;
    fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
}
```
The intuition is similar here, except rather than a `Self: 'a` implied bound, we have a `T: 'a` implied bound. Thus, the data on `Self::Out<'a>` is derived from `&'a T`, and thus it is reasonable to expect that the lifetime `'x` will always be less than `T`.

## Implementation Algorithm ##
* Given a GAT `<P0 as Trait<P1..Pi>>::G<Pi...Pn>` declared as `trait T<A1..Ai> for A0 { type G<Ai...An>; }` used in return type of one associated function `F`
* Given env `E` (including implied bounds) for `F`
* For each lifetime parameter `'a` in `P0...Pn`:
    * For each other type parameter `Pi != 'a` in `P0...Pn`: // FIXME: this include of lifetime parameters too
        * If `E => (P: 'a)`:
            * Require where clause `Ai: 'a`

## Follow-up questions ##
* What should we do when we don't pass params exactly?
For this example:
```rust
trait Des {
    type Out<'x, D>;
    fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
}
```
Should we be requiring a `D: 'x` clause? We pass `Wrap<T>` as `D` and `'z` as `'x`, and should be able to prove that `Wrap<T>: 'z`.

r? `@nikomatsakis`
2021-11-06 04:15:22 +00:00
..
src Auto merge of #89970 - jackh726:gats_diagnostics, r=nikomatsakis 2021-11-06 04:15:22 +00:00
Cargo.toml Migrate to 2021 2021-09-20 22:21:42 -04:00
README.md

For high-level intro to how type checking works in rustc, see the type checking chapter of the rustc dev guide.