Foreword:

Original case I tries to implement is: "Replace all signature's types with associated types in impl block".

Synopsis:

Variance inference looks weird in case described above. When `&'s T`

type is replaced with `Self::AssocT<'s>`

it drives a signature mismatch.

```
trait Test
where
Self: for<'a> Lookup<'a>,
{
fn test<'s>(_: &'s String) -> &'s String;
}
trait Lookup<'s> {
type Arg;
}
impl<'a> Lookup<'a> for () {
type Arg = &'a String;
}
impl Test for () {
fn test<'s>(_: <Self as Lookup<'s>>::Arg) -> <Self as Lookup<'s>>::Arg { // Error: `'s` is not `'s`
todo!()
}
}
```

According to nomicon and dev-guide, by default `'a`

should be late-bounded and contravariant in `fn(&'a T)`

signature, so `Self::AssocT<'a>`

probably changes variance of `'a`

in some cases and its doesn't looks like a normal behavior.

```
trait CovariantLate: Lookup {
fn test<'a>(arg: i32) -> &'a i32;
}
trait CovariantEarly: Lookup {
fn test<'a: 'a>(arg: i32) -> &'a i32;
}
trait ContrvariantLate: Lookup {
fn test<'a>(arg: &'a i32) -> i32;
}
trait ContrvariantEarly: Lookup {
fn test<'a: 'a>(arg: &'a i32) -> i32;
}
// or it is bivariant?
trait InvariantLate: Lookup {
fn test<'a>(arg: &'a i32) -> &'a i32;
}
trait InvariantEarly: Lookup {
fn test<'a: 'a>(arg: &'a i32) -> &'a i32;
}
trait Lookup {
type T1<'a>;
type T2<'a>;
type T3;
}
impl<T: ?Sized> Lookup for T {
type T1<'a> = &'a i32;
type T2<'a> = i32;
type T3 = i32;
}
impl CovariantLate for () {
fn test<'a>(arg: Self::T2<'a>) -> Self::T1<'a> {
todo!()
}
}
impl CovariantLate for ((), ) {
fn test<'a>(arg: Self::T3) -> Self::T1<'a> {
todo!()
}
}
impl CovariantEarly for () {
fn test<'a>(arg: Self::T2<'a>) -> Self::T1<'a> {
todo!()
}
}
impl CovariantEarly for ((), ) {
fn test<'a>(arg: Self::T3) -> Self::T1<'a> {
todo!()
}
}
// errors
// impl ContrvariantLate for () {
// fn test<'a>(arg: Self::T1<'a>) -> Self::T2<'a> {
// todo!()
// }
// }
impl ContrvariantLate for ((), ) {
fn test<'a>(arg: Self::T1<'a>) -> Self::T3 {
todo!()
}
}
impl ContrvariantEarly for () {
fn test<'a>(arg: Self::T1<'a>) -> Self::T2<'a> {
todo!()
}
}
impl ContrvariantEarly for ((), ) {
fn test<'a: 'a>(arg: Self::T1<'a>) -> Self::T3 {
// ^^^^^^ required
todo!()
}
}
// errors
// impl InvariantLate for () {
// fn test<'a>(arg: Self::T1<'a>) -> Self::T1<'a> {
// todo!()
// }
// }
impl InvariantEarly for () {
fn test<'a>(arg: Self::T1<'a>) -> Self::T1<'a> {
todo!()
}
}
```

The workaround is specify `'s: 's`

bound in method definition, but this drives another mismatch in "normal" implementations.

```
trait Test
where
Self: for<'a> Lookup<'a>,
{
fn test<'s>(_: &'s String) -> &'s String
where
's: 's; // Now it is early-bounded.
}
trait Lookup<'s> {
type Arg;
}
impl<'a> Lookup<'a> for () {
type Arg = &'a String;
}
impl<'a> Lookup<'a> for ((),) {
type Arg = &'a String;
}
impl Test for () {
fn test<'s>(_: <Self as Lookup<'s>>::Arg) -> <Self as Lookup<'s>>::Arg {
todo!()
}
}
impl Test for ((),) {
fn test<'s>(_: &'s String) -> &'s String { // Error: `'s` is not `'s`
todo!()
}
}
```