scalatype-parametertype-memberstype-equivalence

Value assigned to type member via method type parameter breaks type equivalence


Why does the following type equivalence hold

trait Foo { type T }
val fa = new Foo { type T = Int }

implicitly[fa.T =:= Int] // OK

but when type member T is assigned via method parameter A then type equivalence does not hold

def makeFoo[A]: Foo = new Foo { type T = A }
val fb = makeFoo[Int]

implicitly[fb.T =:= Int] // ERROR

Intuitively I would expect if T = A and A = Int then T = Int?


Solution

  • This is because the return type of makeFoo is only Foo and not Foo { type T = A }. If you don't explicitly declare it or if you refine it, the error will go away.

    def makeFoo[A] = new Foo { type T = A }
    val fb = makeFoo[Int]
    
    implicitly[fb.T =:= Int] // No more error
    
    or
    
    def makeFoo2[A]: Foo { type T = A } = new Foo { type T = A }
    val fc: Foo { type T = Int } = makeFoo[Int]
    
    implicitly[fc.T =:= Int] // No more error
    

    Scastie:

    <script src="https://scastie.scala-lang.org/knIfPcXqSQKXXCXJ2teHkg.js"></script>