scalagenericstypesscala-2.13

Scala type mismatch error involving generics and refined types


The following is a simplified version of a type-mismatch error I'm trying to solve:

trait Foo[A] {
  type B
  val b: B
}

trait Bar[T, R[_]] {
  val r: R[T]
}

object TypeMismatch extends App {
  def baz[T, U](bar: Bar[T, Foo { type B = U }]): Foo[T] { type B = U } = {
    bar.r
  }
}

The above code produces the following error:

Foo.scala:12: error: type mismatch;
 found   : Foo[T]{type B = U}
 required: Foo[T]{type B = U}
    bar.r
        ^

Any insight regarding how Scala determines the types are mismatched?


Solution

  • Foo { type B = U } is incorrect. You're trying to add type refinement to type constructor while you mean adding type refinement to a proper type and considering corresponding type lambda.

    Try ({type λ[a] = Foo[a] { type B = U }})#λ

    def baz[T, U](bar: Bar[T, ({type λ[a] = Foo[a] { type B = U }})#λ]): Foo[T] { type B = U } = {
      bar.r
    }
    

    https://scastie.scala-lang.org/h8lYBBlpS2WdPVTxKF5JMQ

    With kind-projector this should be λ[a => Foo[a] { type B = U }]

    https://scastie.scala-lang.org/DmytroMitin/I0m86QshRe2k9vee0XPNTw

    In Scala 3 [a] =>> Foo[a] { type B = U }

    https://scastie.scala-lang.org/aYEEeIm4RgKgDHNwYNeVkA

    It's better to introduce Aux-type

    trait Foo[A] {
      type B
      val b: B
    }
    object Foo {
      type Aux[A, B0] = Foo[A] { type B = B0 }
    }
    

    and then write Foo.Aux[*, U] with kind-projector

    https://scastie.scala-lang.org/aSUZUG6eTk2tDLlgczDGqw