So I found some esoteric code when upgrading an old Scala 2 library, the gist of it looks like this:
object MatchExtractTypeArg {
import scala.reflect.runtime.universe.TypeTag
def mapType(k: TypeTag[_], v: TypeTag[_]) = {
(k, v) match {
case (k: TypeTag[a], v: TypeTag[b]) =>
implicit val kkk = k
implicit val vvv = v
implicitly[TypeTag[Map[a, b]]]
}
}
def main(args: Array[String]): Unit = {
val t1 = implicitly[TypeTag[Int]]
val t2 = implicitly[TypeTag[String]]
val r = mapType(t1, t2)
println(r)
}
}
the pattern matching case (k: TypeTag[List[a]], v: TypeTag[List[b]]) is fairly difficult to understand. after some investigation, I could only speculate that the following unapply function was used on k & v to determine type a & b:
// (in scala.reflect.runtime.universe.TypeTag definition)
def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe)
After Scala 3 upgrade, the above code should becomes:
object MatchExtractTypeArg {
def mapType(k: Typeable[_], v: Typeable[_]) = {
(k, v) match {
case (k: Typeable[a], v: Typeable[b]) =>
given kk: Typeable[a] = k
given vv: Typeable[b] = v
summon[Typeable[Map[a, b]]]
}
}
def main(args: Array[String]): Unit = {
val t1 = summon[Typeable[Int]]
val t2 = summon[Typeable[String]]
val r = mapType(t1, t2)
println(r)
}
}
It apparently compiles without a problem, but when trying to figure out its mechanism, I found that the unapply method being defined under Typeable has an entirely different signature, and can't extract any type argument.
Am I not upgrading code properly? How could it be possible that the new extractor still works in Scala 3?