---
# System prepended metadata

title: Reviewing early- / late- bound PR changes

---

# 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?


