# GATs ahoy (1.0)
* [GATs Ahoy 2.0](https://hackmd.io/sxZENS1GTbil8qTTtgzQjQ)
## 2021-12-13
* What needs to happen
* GAT triage
* Potential experiments
* "what do people do when they're not instructed what to do"
* "harm of getting it wrong is so low"
* auto-fix will do it
* Stalled
* Where clause syntax
### Jack's PR
* introduces a mode to AssocTypeNormalizer that falls back for inference variables
```rust
// Crate A
struct Set<K: Eq + Hash> { }
impl<K> Set<K> {
fn insert(&mut self, value: K) {
let hash = Hash::hash(&value);
...
}
}
// Crate B
```
## 2021-11-29
### Niko's master plan
```rust
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item
where
Self: 'me;
fn iter(&self) -> impl Iterator + '_;
}
```
```rust
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item
/* implied: */
where Self::iter<'me>::Item: OK;
fn iter(&self) -> impl Iterator + '_;
}
type Item<Self, 'me> = Self::iter<'me>::Item
/* implied: */
where Self::iter<'me>::Item: OK;
```
* Current "default bounds requirement"
* we check currently that the bounds are present
* exactly in the form expected
* but better would be to check that they can be proven
* in the environment of the trait
* To do the above design, need to include:
* implied bounds of `T: OK` include `WF(T)`
* [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=32bcd25cf9c0f2671233b6c58ff784d9) -- error: hack
* [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=d22f40fef3cb9f37ebbac07af585cb99) -- removed Eq bound, gets error
*
### "Jack's issue"
* #87748
* Jack's previous solution
* treat unnormalized types in fn sig as "wf"
* seemed ok but we missed something
* implemented in PR #88312
* But #91068 filed 10 days ago
* Related to https://github.com/rust-lang/rust/issues/25860
* Jack's expected solution
* projection type is WF if all input types are
* self type has to be WF
* but it doesn't have to be *constructed*
* https://github.com/rust-lang/rust/blob/8b954910c59a7a362c60959e93110892b6e9a691/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs#L39-L47
* https://github.com/rust-lang/rust/blob/8b954910c59a7a362c60959e93110892b6e9a691/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs#L112-L116
* when you call a function f with arguments of type A0...An:
* we check that the expected types of those arguments E0...En are WF
* Why is #25860 unsound?
* `T1 <: T2` does not imply `WF(T1) <=> WF(T2)` (or maybe vice versa)
* `Normalize(T) => U` does not imply `WF(T)` and `WF(U)` have entailment relationship
*
## 2021-11-22
### Thoughts on associated types, implied bounds
```rust
trait Foo {
type method<'me>: Trait;
fn method(&'me self) -> Self::Trait<'me>;
}
```
Effect on inference?
* We only do the inference when the GAT is a return type
* Iterated inference
```rust
trait Foo {
// what type do we introduce now?
fn method(&self) -> (impl Debug, impl Debug);
}
```
```rust
trait LendingIterable {
type Item<'me>;
type Iter<'me>: Iterator<Item = Self::Item<'me>> + 'me;
fn iter(&self) -> Self::Iter<'_>;
}
trait LendingIterable {
type Item<'me>;
fn iter(&self) -> impl Iterator<Item = Self::Item<'_>> + '_;
}
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item;
fn iter(&self) -> impl Iterator + '_;
}
```
```rust
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item
where
Self: 'me;
fn iter(&self) -> impl Iterator + '_;
}
```
```rust
type Item<Self, 'me> = impl Sized + 'me;
// use it in such a way that Self: 'me was required
// --> results in an error
```
```rust
trait WellFormed { }
impl<T: ?Sized> WellFormed for T { }
final type Item<'me> = Self::iter<'me>::Item
where
Self::iter<'me>::Item: std::marker::WellFormed;
```
---
```rust
trait WellFormed { }
impl<T: ?Sized> WellFormed for T { }
// input from user:
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item;
fn iter(&self) -> impl Iterator + '_;
}
// desugars to:
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item
where
Self: 'me; // <-- user will have to add this
final type Item<'me>
where
Self: 'me // <-- user will have to add this
= Self::iter<'me>::Item;
type iter<'me>: Iterator + '_
where
&'me Self: std::marker::WellFormed,
A1: WellFormed,
...,
An: WellFormed;
fn iter(&self, ...) -> impl Iterator + '_;
}
```
---
* introduce a type alias for the method's return type
* xxx what about impl trait that is not at the root?
* for that type alias, we add `where T: WellFormed`
* add a `std::marker::WellFormed` trait
* add `final` in traits
* show how this will be useful for specialization
* in an impl:
* things are `final` by default
* can be declared `default`
* in a trait
* things are `default` by default
* can be declared `final`
* you will have to write `where Self: 'me` in the trait definition
* Unrelated, but:
* Niko thinks we should support
* `type Foo: Iterator` at the module level too :)
###
https://github.com/rust-lang/rust/issues/90573
### Jack's thing
- Try to normalize associated types before processing obligations
- [#90887](https://github.com/rust-lang/rust/pull/90887)
- Two obligations O1 and O2 that feature a projection with an inference variable
- In O2 we find a type for the inference variable
- But when we go back to try and prove O1 we don't try to normalize again using the knowledge of the inference variable
## 2021-11-15
### Where the where
* jack: In a vacuum, changing the where clauses on GATs is the right decision
* but for consts and functions...it feels more awkward
* expressions can get long in consts
* overall I feel on the fence
* maybe consult about how to drive this in a more data-oriented way
### Outlives lint
* no changes since last week
* Bug?: https://github.com/rust-lang/rust/issues/90808
```rust
#![feature(generic_associated_types)]
trait MyTrait {
type AT<'a>;
}
struct Outer<'a, T>(&'a T);
impl<'a, T: MyTrait> MyTrait for Outer<'a, T> {
type AT<'b> = T::AT<'b>; // Switching this to T::AT<'a> works
}
trait Ops<T> {
}
fn g<'this, O, T>(x: &'this O)
where
O: MyTrait,
T: Ops<O::AT<'this>>, // Commenting this line makes this compile
{}
fn f<'this, I, T>(x: &'this I)
where
I: MyTrait,
T: Ops<I::AT<'this>>
{
let outer = Outer(x);
g::<_, T>(&outer); // Should this be allowed?
}
```
https://github.com/vandenheuvel/relp/commit/aa471b3272cb53f8f497217585f89599cc9343c3
https://github.com/rust-lang/rust/issues/90713
https://github.com/rust-lang/rust/pull/90887
Niko's question:
* Where did this `F: 'static` come from ([code](https://github.com/vandenheuvel/relp/blob/aa471b3272cb53f8f497217585f89599cc9343c3/src/algorithm/two_phase/matrix_provider/matrix_data.rs#L281-L288))?
* Guess:
* error from not being WF led to it being included
## 2021-11-08
* Planned
* Where the where
* FCP didn't get picked up
* Centril's proposal to abbreviate `fn foo() { result }` to `fn foo() = result;`
* Some [concerns](https://github.com/rust-lang/rust/issues/89122#issuecomment-962619847) about rustfmt
* Outlives lint
* What rule to apply when GAT appears in bounds of another GAT? See [test](https://github.com/rust-lang/rust/pull/89970/files#diff-75725c2c489f166d10b6f2d5d922249e1d3e5d318db9bcf6a89fee50616f4e4cR141)
* What clause do we want when lifetime in trait? see [test](https://github.com/rust-lang/rust/pull/89970/files#diff-75725c2c489f166d10b6f2d5d922249e1d3e5d318db9bcf6a89fee50616f4e4cR113)
## what rule to apply...
* we definitely want this
* we wanted fixed point
* the algorithm is roughly like so
* For a trait T
```
required bounds is a set (TypeName<'a> where WC...)
required_bounds = {}
loop {
required_bounds1 = infinity
for each item in the trait
required_bounds1 = required_bounds1 intersect required(required_bounds, item)
if required_bounds != required_bounds1 {
required_bounds = required_bounds1;
} else {
break;
}
}
required(_, fn() -> T) =
search return type T for appearances of GAT
required(b, type Foo<..>: Bounds) =
* as today but where we search Bounds for appearances
* include b in the environment
```
### question: why limit ourselves to return type?
can we come up with a realistic example?
```rust
trait Searchable {
type Item<'a>;
fn contains<'a>(&'a self, item: Self::Item<'a>);
}
```
## where the where examples
```rust
const Foo<T>: Type = value
where T: Bar;
const Foo<T>: Type = match {
} where T: Bar;
fn foo<T>() -> Type = value
where T: Bar;
fn foo<T>() -> Type
where T: Bar;
fn foo<T, U>() -> Type
where
T: Bar,
U: Baz,
{
match {
...
}
}
fn foo<T, U>() -> Type
where
T: Bar,
U: Baz,
= match {
...
}
fn foo<T: Bar, U: Baz>(
) -> Type = match {
...
}
```
## 2021-10-23
* Planned topics
* Open PRs
* [#89970](https://github.com/rust-lang/rust/pull/89970)
* [#90017](https://github.com/rust-lang/rust/pull/90017)
* [#90076](https://github.com/rust-lang/rust/pull/90076)
* [#88441](https://github.com/rust-lang/rust/pull/88441)
* Needs comment
* [#87735]
* 2 blocking issues for GATs (outlives & where)
* [#89352](https://github.com/rust-lang/rust/issues/89352) "untriaged", but probably not blocking
* [#90076]
* Change to `Generics` + `usize`
* [#89970]
* Add a link in error message to initiative
### case niko is talking about
```
impl<A, B> Foo for A
whereu
}
```
## 2021-10-18
* PR: [#89970](https://github.com/rust-lang/rust/pull/89970)
* Implemented using the lexical checker, but works
* Interaction of impl trait and GATs?
* [play](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9942a411c5d63023a7f0e7523bc86b81)
* Danger of this setup
* If the compiler gets smarter, and is better able to prove outlives bounds, then it can be a breaking change
* more things need to be declared
* in the future, more defaults, which are *less* of a breaking change
* Generally something we try to avoid
* Along those lines:
* normalization
* semi-cyclic reasoning
* the where clauses we are inferring influence the "wf" condition
* if we have implied bounds...
* the implied bounds of the GAT might be its where clauses
* and we are inferring those where clauses with implied bounds in scope
* what this argues:
* we can move forward but using an error is a good setup
* more comfortable making this a default once we've moved to chalk
* Possibilities
* Normalized type has *fewer* than the unnormalized type
* `()`
* Can it have *more*?
* Argument: No
* The WF requirements of the value of an associated type must be implied by the where clauses on the impl
* So if we can successfully normalize, we must know those where clauses hold in some other way
```rust
trait Ref1<'a> {
type T;
}
impl<'a, T> Ref1<'a> for T {
type T = &'a T;
}
trait Ref2 {
type T<'a> /* where Self: 'a inferred, in principle */ ;
fn blah(&self) -> Self::T<'_>;
}
impl<T> Ref2 for T {
type T<'a> = &'a T;
}
```
```rust
trait Foo {
type Iter<'a>;
fn foo(s: <Self as Ref2>::T<'a>) -> Self::Iter<'a>;
// normalized: `s: &'a Self'
}
```
```rust
trait Foo {
type Iter<'a>;
fn foo(&self, x: ) -> Self::Iter<'a>;
}
trait Ref<'a, T>
where T: 'a
{
type T = &'a u32;
}
```
### Where the where clauses are
a la "Where the wild things are"
Not such a trivial change. When we are parsing (and lowering), we don't keep track of whether it's an associated type or a top-level type alias. Need to stay backwards compatibility.
Kind of annoying. Probably want to parse both and append them together in HIR lowering and then report errors in AST validation.
### Normalize closure
https://github.com/rust-lang/rust/pull/88441
in this logic:
https://github.com/rust-lang/rust/blob/5dab47dcd8267b8769421b46532414ec36d625e3/compiler/rustc_trait_selection/src/traits/project.rs#L476-L483
* if `normalized_ty` is an inference variable
* that was introduced by the projection code
* and will eventually be inferred to a placeholder `'a` representing one of the higher ranked regions in question
* *then* that placeholder will not be replaced
we thought that was not possible but we were wrong:
```rust
trait Foo {
type Output;
}
trait Bar {
type Output;
}
impl<A, B> Bar for A
where
A: Foo<Output = B>,
{
type Output = B;
}
impl<T> Foo for T {
type Output = T;
}
```
Scenario:
* Normalizing `for<'a> <&'a u32 as Bar>::Output`
* expected result: `for<'a> &'a u32`
what we wind up doing today:
* replace `B` with `?B` and generate a obligation
* `A: Foo<Output = ?B>`
* result is `?B` with:
* `&'!a u32: Foo<Output = ?B>`
* once we're done proving everything we have `?B = &'!a u32`
conclusion:
* orthogonal issue with various ways to fix
* investigate to see why NLL works but we can conceivably land and
* file a follow-up bug for this issue
## 2021-10-11
### Proposed defaulting 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 parameter `Pi != 'a` in `P0...Pn`:
* If `E => (P: 'a)`:
* Require where clause `Ai: 'a`
### Example A
```rust
trait Iterable {
type Iter<'x>;
fn iter<'me>(&'me self) -> Self::Iter<'me>;
// Requires: Self: 'x
}
```
### Example B
```rust
trait Des3 {
type Out<'x, D>;
fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
// Requires: D: 'x
}
```
### Example C
```rust
trait Des3 {
type Out<'x, D>;
fn des<'z, B: Deref<Target = A>, A>(&self, data: &'z B) -> Self::Out<'z, A>;
// Requires: (nothing)
//
// but if we extend Deref with an "implied bound" of `for<'a> (Self: 'a => Self::Target: 'a)`
// then it would require `D: 'x`
}
```
### Example D
```rust
trait Deserializer<T> {
type Out<'x>;
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
// short for:
fn deserialize<'a>(&self, input: &'a T) -> <Self as Deserializer<T>>::Out<'a>;
// Requires `T: x`
}
impl<T> Deserializer<T> for () {
type Out<'a> = &'a T;
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input }
}
```
### Example E
```rust
trait Trait<T> {
type Out<'a>;
fn make<'a>(&self, input: &'a Vec<T>) -> Self::Out<'a>;
}
```
### Implementation strategy
* Add a new query that constructs the borrow check / type check data structures
* gives them their implied bounds
* tries to prove `Generic: 'a`
* and reports back provable or not provable
* https://github.com/rust-lang/rust/blob/86d6d2b7389fe1b339402c1798edae8b695fc9ef/compiler/rustc_borrowck/src/type_check/mod.rs#L126-L139
* https://github.com/rust-lang/rust/blob/86d6d2b7389fe1b339402c1798edae8b695fc9ef/compiler/rustc_borrowck/src/type_check/mod.rs#L154-L164
## 2021-10-04
* This week:
* Niko
* Friday: outlives default inference
* Dig further into #88441
* Jack
* What blocks stabilization?
* Default inference
* Where clause syntax
* Have to resolve questions about trait aliases
* Explainer
* Bugs and test case coverage
* Triage and label
* GATs-triaged
* GATs-blocker-1
* What can we do to increase confidence?
* Modeling specific use cases?
* The graph iterator thing, port to use GATs
* Async fns in traits
* procedural macro that desugars
* https://crates.io/crates/real-async-trait
* Notes
* Nearly all bugs labeled GATs are "things we can't readily fix that arise more with GATs"
* e.g. changes are early to late bound
* something something overflow
*
* Pending issues
* #89242
* Where we start to have problems: https://github.com/rust-lang/rust/blob/a4797664ba9c7d71e586122853858eeb6c153bb9/compiler/rustc_typeck/src/check/callee.rs#L85
* Confusing things
* #89196
* Not a regression
*
## 2021-09-20
* Niko this week:
* Investigate #88441, why does this behave differently with NLL?
* Open an issue about changing the syntax (which repo?)
* Digression about member constraints
* Does falling back to static create a backwards incompatibility?
* Niko's argument: no
* The restriction comes late in type checking
* Can influence borrow checking but
* if the region comes from a borrow, that's an error either way
* if the region comes from a reference, there is an upper bound (and hence PR doesn't apply)
* unless it comes from a static reference, in which case it's a fine choice
* Crater run
* #88441
* Did we always need a normalization here?
* Jack thinks yes
* Issue 62529-1 output changes
* We are now able to infer a type successfully, no longer get a type mismatch
* Issue 70120
* Got an error before, but no longer do
* Gets us closer to #88382
* Branch: https://github.com/jackh726/rust/tree/issue-88459
* Minimized issue: `src/test/ui/generic-associated-types/issue-88459-2.rs`
* Log: https://gist.github.com/jackh726/a5e6c62dd1e76a28ab9491aa5d4e5079
* [Debugging session](https://pernos.co/debug/aXf8Fomk39i3jbzQrsAsDQ/index.html#f{m[Xpo,AA_,t[AQ,FeUG_,f{e[Xpk,WA___/)
### Issue 88382
```rust
#![feature(generic_associated_types)]
trait Iterable {
type Iterator<'a>;
fn iter(&self) -> Self::Iterator<'_>;
}
struct SomeImplementation();
impl Iterable for SomeImplementation {
type Iterator<'a> = std::iter::Empty<usize>;
fn iter(&self) -> Self::Iterator<'_> {
std::iter::empty()
}
}
fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
f(&mut i.iter());
}
fn main() {
do_something(SomeImplementation(), |_| ());
do_something(SomeImplementation(), test);
}
fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
```
## 2021-09-13
* Normalize obligation for closure confirmation:
* https://github.com/rust-lang/rust/pull/88441
* Recursive issue
* https://github.com/rust-lang/rust/issues/87755
* This compiles
* https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=cd0d44d930eead0c705d6eeeafa22be7
* not gat blocking
* Changes to default decision
* move the ruled out options away
* add example of `Iter<'static>`
* add "opt-out" discussion, with `where` as the opt-out?
* Where clause syntax
* Open an issue and start an FCP for T-lang to change the syntax
* Type aliases -- keep it unstable until they have the desired semantics
* chalk-ty
* problem is that we are no longer variant over the lifetime
* but we have `'static` stuff that we try to use
* how to handle variance and subtyping?
* can we do field-by-field comparisons?
* two ways to fix
* change how we handle variance, assoc types in some way
* add a lifetime to the interner trait
* closure normalization issue
*
## 2021-08-30
* New PR [#88441]
* New bug related to #85499: [#88446]
* Starting looking at [#87755]
* Don't know if there's anything to discuss; haven't actually done much
[#88441]: https://github.com/rust-lang/rust/pull/88441
[#88446]: https://github.com/rust-lang/rust/pull/88446
[#87755]: https://github.com/rust-lang/rust/pull/87755
## 2021-08-23
* Last week
* PR [#87900]
* Removed special case for adding the predicate into the environment
* Works except for `default` and default associated types in traits
```rust
trait Family {
type Member<C: Eq>;
}
impl Family for VecFamily {
type Member<C: Eq> = i32;
}
// would generate a clause like
forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
// which is wrong, we want
forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
```
Hypothesis:
Although the first clause can be used with types `C` that do not implement `Eq`, for it to cause some kind of problem, there would have to be a `VecFamily::Member<X>` for some type `X` where `!(X: Eq)`, that appears in the value of `type Member<C: Eq> = ...`. That type would fail a well-formedness check that we ought to be doing elsewhere, which would check that any `<T as Family>::Member<X>` meets the bounds declared in the trait (notably, that `X: Eq` and `T: Family`).
```rust
trait Family {
type Member<C: Eq>: MyBound<C>;
}
trait MyBound<C> { }
impl<C: Eq> MyBound<C> for i32 { }
impl Family for VecFamily {
type Member<C: Eq> = i32;
}
// would generate a clause like
forall<X> { Normalize(<VecFamily as Family>::Member<X> => i32) }
// Environment like
// a. !C: Eq
// b. forall<X> { Normalize(<VecFamily as Family>::Member<X> => i32) }
// where !C = TyParam(C)
// Goal is to prove
//
// `i32: MyBound<!C>`
//
// will instantiate rule b with X = !C
```
### Categorizing our work
* https://rust-lang.github.io/wg-async-foundations/vision/roadmap/async_fn/async_fn_fundamentals.html
* This work needs to be retconn'd into an initiative
* Niko to setup a repo and so forth
### And now for something completely different

https://github.com/rust-lang/rust/pull/88149#issuecomment-902268188
### #87735
https://github.com/rust-lang/rust/issues/87735
* https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=ca7c842d7fb8005e51d161f4553ccfae
* non-GATs: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=17d005614ab38b7b20280bbc6f8077b8
* conclusion:
* orthogonal-ish, needs an extension for implied bounds or other improved reasoning, blocked on chalk progress
* two problems at play:
* what we would need to do for this to work:
### This week, goals
* Jack:
* [x] Jack to add above as comment into #87900 with test
* Niko:
* [x] Review https://github.com/rust-lang/rust/pull/85499
* [x] Review #87900 once comment is added and r+
* [x] Retconn GATs Ahoy into an initiative
* [ ] Write a comment for #87735
[#87900]: https://github.com/rust-lang/rust/pull/87900
[#87735]: https://github.com/rust-lang/rust/issues/87735
## 2021-08-16
Updating Niko on recent events:
* Blog post went live (:tada:)
* Folks were excited, as expected ([reddit thread](https://old.reddit.com/r/rust/comments/ox9re0/the_push_for_gats_stabilization/))
* ["holy shit it's happening"](https://old.reddit.com/r/rust/comments/ox9re0/the_push_for_gats_stabilization/h7lb89i/)
* Some issues and PRs to discuss
* 8 reported issues
* some overflow issues
* one that will get fixed with the "normalize under binders" PR
* sized coinductiveness related issue
* early vs late bound:
* because the GAT is not normalized, you get early bound
* some "actual" GAT issues
* Pending PRs
* normalize under binders PRs
* https://github.com/rust-lang/rust/pull/85499
* Use bound vars for GAT params in param_env in check_type_bounds
* https://github.com/rust-lang/rust/pull/87900
* Currently, because of specialization, we are generating predicates like
* `<P0 as Trait<P1..Pn>>::Foo --normalizes-to--> U` when we have `type Foo = U` in the impl (regardless of whether it is default or not)
* it is needed when `default type Foo = U`
* Niko's contention: it is not needed when not default, because the program clause from the impl applies
* Problem occurs when extending to GATs
* In the example from #87429
* We currently generate (on master)
* `<I32 as Family>::Member<'a> --> i32` where `'a` is the early-bound region (which will act as a placeholder when present in the param env)
* Then we try to prove `<I32 as Family>::Member<'a>: for<'b> PartialEq<<I32 as Family>::Member<'b>>`
* this obligation comes from the trait, which declares `type Member<'a>: for<'b> PartialEq<Self::Member<'b>>`
* There are two normalizations required here:
* `<I32 as Family>::Member<'a>` matches the inserted predicate exactly, so we get `i32` and everything is fine
* create a placeholder `!b` and try to normalize `<I32 as Family>::Member<!b>`
* here we apply the `ParamEnv` rule ("because we are dumb")
* `!b = 'a`
* and this is not possible, so we wind up with some sort of error somewhere along the line
* If we did not add to the param env at all:
* we would find the impl, replace all early-bound regions with fresh inference variables
* `<I32 as Family>::Member<?a> = i32`, we would unify this with `...` and get `!b = ?a`, which is fine
* normalize to `i32` (which doesn't reference `!b`)
* we have to prove `i32: PartialEq<i32>`, which is true
* Niko's proposed fix
* If there is no default, do not modify the environment
* If there is a default, and a GAT, report an error
* open a FIXME to resolve this in the "post chalk glorious future"
* The example is below
```rust
trait Family {
type Member<C: Eq>;
}
impl Family for VecFamily {
type Member<C: Eq> = i32;
}
// would generate a clause like
forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
// which is wrong, we want
forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
```
can we make a test case where it actually goes wrong? not obvious.
## 2021-07-19
Busy weekend!
### New PRs
- Pretty placeholders: https://github.com/rust-lang/rust/pull/87246
- Diagnostics for implicit static mismatch: https://github.com/rust-lang/rust/pull/87244
### Blog post
Blog post: https://hackmd.io/FuAvMj4ITLmqmfio47ZF3Q
### What comes next?
* Some time getting feedback and making sure that everything is stable
* Three known issues that are relevant
* "When there's an implicit static, diagnostics are bad" -- easier to hit with GATs -- PR #87244
* Cycle that we hit with Sized bounds -- not a GATs issue, but it may be easier to hit with GATs
* Easiest solution: make Sized coinductive
* Note that that the induction is actually meaningful here, since we don't want infinite size
* Link to issue [#80626](https://github.com/rust-lang/rust/issues/80626)
* Last issue is [#81487](https://github.com/rust-lang/rust/issues/81487), discussed below
* feels like a GATs bug
* somehow related to region inference
* Stabilization report
* Derive tests and check that they are contained
* Set of patterns and expected uses that we expect to work
* Iterable `trait Iterable { type Item; type Iter<'i> where Self: i; fn iter(&self) -> Self::Iter<'i> }`
* GATs with futures
* Something with type parameters
* Test with const maybe?
* Port the rustc-data-structures traits?
* https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/trait.GraphSuccessors.html
* https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/trait.WithPredecessors.html
* Extend the "normalize under binders" to all projections?
* Regression in diesel-doc-bench probably top blocker
* Query normalize is still getting passed escaping bound vars
* If you do this more generally, it crops up when building docs
* Perhaps a better approach
* Figure out how many universes we need and treat it "as if" we had passed through the binder
* This is a reasonable hack, but still a hack
* e.g. if we extend `forall` to carry where clauses, it wouldn't work
* May cause a perf regression
### Issue 81487
```rust
#![feature(generic_associated_types)]
struct IntRef<'a>(&'a mut i32);
trait Trait {
type Ref<'a>;
}
impl Trait for () {
type Ref<'a> = IntRef<'a>;
}
struct RefWrapper<'a, T: Trait>(&'a mut <T as Trait>::Ref<'a>);
fn wrap<'a, T: Trait>(the_ref: &'a mut T::Ref<'a>) -> RefWrapper<'a, T> {
RefWrapper(the_ref)
}
fn main() {
let mut x = 3;
let mut int_ref = IntRef(&mut x);
let wrapper = wrap::<()>(&mut int_ref);
*wrapper.0.0 = 2;
}
```
Error:
```rust
error[E0309]: the associated type `<T as Trait>::Ref<'_>` may not live long enough
--> x.rs:16:5
|
16 | RefWrapper(the_ref)
| ^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Trait>::Ref<'_>: 'a`...
= note: ...so that the type `<T as Trait>::Ref<'_>` will meet its required lifetime bounds
```
Ending up with these bounds (in lexical region resolve):
```
AnyBound([
AnyBound([
IfEq(
<T as Trait>::Ref<'a>,
OutlivedBy(ReFree(DefId(0:13 ~ issue_81487[fb0e]::wrap), BrNamed(DefId(0:14 ~ issue_81487[fb0e]::wrap::'a), 'a)))
),
IfEq(
<T as Trait>::Ref<'a>,
OutlivedBy(ReFree(DefId(0:13 ~ issue_81487[fb0e]::wrap), BrNamed(DefId(0:14 ~ issue_81487[fb0e]::wrap::'a), 'a)))
)
]),
AllBounds([OutlivedBy('_#0r), AnyBound([OutlivedBy(ReEmpty(U0))])])
])
```
but our actual type
`<T as Trait>::Ref<?0>`
Member constraints:
```
DEBUG rustc_infer::infer::lexical_region_resolve Constraint 0 => VarSubVar('_#0r, '_#0r)
DEBUG rustc_infer::infer::lexical_region_resolve Constraint 1 => RegSubVar(ReFree(DefId(0:13 ~ issue_81487[fb0e]::wrap), BrNamed(DefId(0:14 ~ issue_81487[fb0e]::wrap::'a), 'a)), '_#0r)
DEBUG rustc_infer::infer::lexical_region_resolve Constraint 2 => VarSubReg('_#0r, ReFree(DefId(0:13 ~ issue_81487[fb0e]::wrap), BrNamed(DefId(0:14 ~ issue_81487[fb0e]::wrap::'a), 'a)))
```
Gist: https://gist.github.com/jackh726/92f92384bd5e878ca9741169779849fb
* Sounds like we're missing an implied bound
* Niko had a misconception
* `&'a T::Foo` in the arguments
* tells you that `T::Foo: 'a` can be implied
* it does not tell yo that `T: 'a` is true
* although, if you *did* know that `T: 'a` were true, then you would also know that `T::Foo: 'a`
* given `T::Ref<'x>`...
* if `'x == 'a` then `T::Ref<'x>: 'a` can be assumed
* we are not inferring `'x` to `'a`
* might be related to member constraints
### Branching out from GATs (uh-oh)
* lcnr had a different approach in #84944 that moves some of the "dedup" code to project
* Revert save subobligations that had gone through crater
* got closed, found regressions
* changing where it got done
* leads to a big perf improvement
* interacts, maybe ask Aaron1011 to do a first review
* Charles Lew's PR on vtables #86461 needs review
* niko should review, added test attribute which looks great
* ty-interner PR #86435 (LeSeulArtichaut)
* kind of stuck in some lifetime errors, maybe the variance changed?
* needs detailed examination
## 2021-07-12
### Discussing the PR to do normalization
https://github.com/rust-lang/rust/pull/86993
* Perf results are a bit of a mystery, but the result is common between this PR and the other one
* Separate out the changes to the WF
```
Normalize(<P0 as Foo>::Trait<P1..>) = ?T
for<'a> fn(<P0 as Foo>::Trait<'a>)
* if this is normalized to a variable, we are "screwed"
```
* when would we actually return an inference variable
* *and in particular* a variable that does not appear in the input
* the PR uses `opt_normalize_projection_type`, not `normalize_projection_type`
* looking at `project_type`
* `impl<A> Foo for ... { type Assoc = A; }`
* hopefully the builtin rules follow a similar logic
* proof by contradiction:
* it would be unsound for associated type to have an unbound variable because the value of an associated type is supposed to be a pure function of its inputs
* and other parts of the type system assume that to be true
* this value gets returned to `AssocTypeNormalizer`
* true by inductive hypothesis
* in the case of *trait selection error*
* we create a new variable and return it
* the PR
* what we want to avoid:
* that a late-bound variable appears in the output but is hidden under some inference variable whose value is not yet known
* why?
* `literate_late_bound_regions` currently just ignores inference variables, on the premise that they cannot name a late-bound region
* PR one:
* well-formedness logic is in the wrong order
* does this regress performance??
* in the case of error, return the original type, not a fresh inference variable
* do we really this? it's independent
* [existing logic](https://github.com/rust-lang/rust/blob/c63f1fe92b99a9828e9f999355213b0b73175aa0/compiler/rustc_trait_selection/src/traits/project.rs#L969-L990) (return an unbound inference variable) is already unsound
* layout code and bound variables
* `struct Foo { x: <fn(&u32) as Foo>::Bar }`
```rust=
impl Foo for fn(&u32) {
type Bar = i32;
}
impl<'a> Foo for fn(&'a u32) {
type Bar = u32;
}
```