Search code examples
scalaexistential-type

Why scala does not unify this type lambda with underlying type?


trait A {
  type T
  def test(t: T): Unit
}

case class B[S <: A](a: S, t : S#T) {
  def test() = a.test(t) // Error: type mismatch;
    // found   : B.this.t.type (with underlying type S#T)
    // required: B.this.a.T
}

Am I wrong to expect the above to compile? Can my code be fixed?


Solution

  • Compiler has not sufficient evidence that S#T can be used as argument for test in concrete instance.

    Consider this hypotecical example for weakened scala compiler

    trait A2 extends A{
      type T <: AnyRef
    }
    
    class A3 extends A2{
      override type T = Integer
    
      def test(t: Integer): Unit = println(t * 2)
    }
    

    So B[A2] should accept instance of A3 along with anything that is <: AnyRef while A3 needs exactly Integer for its own test implementation

    You can catch concrete type in the definition of B, to make sure what type will be used

    case class B[S <: A, ST](a: S {type T = ST}, t: ST) {
      def test() = a.test(t) 
    }