# Reviewing early- / late- bound PR changes
## Topic
https://github.com/rust-lang/types-team/issues/62
## Meeting conclusions
### How do we represent the type of a function?
In this example...
```rust
fn foo(x: &u32) { }
let y = foo;
```
What is the type of `y`? It has to be a `FnDef` type, but the region for `x` should be higher-ranked, and right now our `Ty` structure can't represent that (you would need a `Binder<FnDef>`).
Other examples to talk through:
**Coercion to a higher-ranked fn pointer.**
```rust
fn foo(x: &u32) { }
let y = foo;
let z: fn(&u32) = y;
```
### Impl / trait mismatch
This is nice, we like writing patterns like this
```rust
trait Foo<T> {
fn take(&self, x: T);
}
impl Foo<&u32> for () {
fn take(&self, x: &u32) { ... }
}
// where elided lifetimes are
trait Foo<T> {
fn take<'a>(&'a self, x: T);
}
impl<'b> Foo<&'b u32> for () {
fn take<'a, 'c>(&'a self, x: &'c u32) { ... }
}
```
but how to manage in a principled way?
[More examples](https://rust-lang.zulipchat.com/#narrow/stream/326132-t-types.2Fmeetings/topic/2023-03-20.20types-team.2362/near/343139824)
**Impl detail.** One way to do it is by "desugaring" impl to something like this
```rust
trait Foo<T> {
fn take(&self, x: T);
}
impl<'a> Foo<&'a u32> for () {
fn take(&self, x: &'a u32) { /* matches trait */
fn helper(&self, x: &u32) { /* exactly as user wrote it */ }
helper(self, x)
}
}
```
i.e., the "public" signature is the same as trait.
**Mapping.** Other idea would be to try and create a mapping between lifetimes, but that can be tricky. e.g. consider this example
```rust
trait Foo {
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) { }
}
impl Foo for () {
fn foo<'x>(x: &'x u32, y: &'x u32) { }
}
```
which would require `'x` be mapped to `'a & 'b`
## Random notes
### nikomatsakis
**Niko's ideal.** No difference between early- vs late-bound, just have generics.
FnDef type:
```rust=
fn foo<'a, T>(...)
where
T: Trait<'a>
```
the type of `foo` would be `for<'a, T> if (T: Trait<'a>) fn(...)`.
Coercing from a type like the above to a fn pointer would entail some rules not unlike today's early- vs late- bound. Haven't though this all the way out.
**Thoughts on the PR.**
**Are there complications?**
Questions to answer:
* Today:
* Does this have surprise interacts or admit new patterns of code?
* Does this move us closer to the architecture we want?
* Tomorrow:
* What rules do we want so as to achieve "everything is just generics"?
* In particular, how to manage "changing amount of late-bound lifetimes between trait/impl"
### lcnr
longterm everything should be late-bound. reviewing that PR is confusing because it's from before we added `EarlyBinder`. "Notably, changing the amount of late-bound lifetimes between trait and impl is allowed" is really annoying. https://github.com/rust-lang/rust/pull/108782#issuecomment-1472523987 there's this comment on a related PR and...
we have:
- it is possible to have a different amount of late bound lifetimes between impl and trait method
- longterm everythign should be late bound
how would we actually unify this going forward?