Can't use a type projection to a recursive (f-bounded) type

63 views Asked by At

I am getting a type error which I don't understand, when using a projection from one f-bounded type to another. It might be related to an earlier question but I'm not sure.

The setup is simple:

trait Foo[F <: Foo[F]] {
  type I <: Foo[I]
}

That is, I have a system F that contains a projection to another similar system.

Ok, now what I need to do is, given F, be able to use F#I. But the compiler complains:

trait Test {
  def apply[F <: Foo[F]]: Unit = bar[F#I]   // type error
  def bar  [F <: Foo[F]]: Unit = ???
}

<console>:52: error: type arguments [F#I] do not conform to method bar's 
  type parameter bounds [F <: Foo[F]]
             def apply[F <: Foo[F]]: Unit = bar[F#I]
                                               ^

So why is this? And is there a solution?


Actually, it seems to be a variant of this problem which doesn't explain what is going on.


Edit: For example, the following compiles:

trait Test {
  def apply[F <: Foo[F] { type I = I1 }, I1 <: Foo[I1]]: Unit = bar[I1]
  def bar  [F <: Foo[F]]: Unit = ???
}

Now the problem is, that shitty type parameter I1 will bubble up through dozens of levels in my API, so I really need to find a solution that avoids a second type parameter.

1

There are 1 answers

0
0__ On

Ok, so I went through my existing code base, until I found this work-around used before:

trait Foo[F <: Foo[F]] {
  type I  <: Foo[I]
  type Tx <: Txn[F]
}

trait Txn[F <: Foo[F]] {
  val foo: F
}

trait Test {
  def apply[F <: Foo[F]](implicit tx: F#Tx): Unit = {
    val foo: F = tx.foo
    bar[F, foo.I](tx)
  }

  def bar[F <: Foo[F], I <: Foo[I]](implicit tx: F#Tx): Unit = ???
}

That is, I need to have a value from which I get a path-dependent type, and then the typer is happy again.

I'm still very interested to understand why my original code is rejected.