I am trying to build a map from an input map, but the compiler is unable to prove that a 2-element tuple is a 2-element tuple.
Code
class Element[T] extends AnyRef { }
class Sample
{
def makeList(x:Int): Element[_] = {
x match {
case 1 => new Element[Boolean]
case 2 => new Element[(Boolean, Boolean)]
}
}
val input = Map(1 -> "one",2 -> "two")
val output = input.map(e => e._1 -> makeList(e._1)).toMap
}
sbt compile
sbt:root> ~compile
[info] Compiling 1 Scala source to /Users/tda0106/test/scala/target/scala-2.12/classes ...
[error] /Users/tda0106/test/scala/src/main/scala/Test.scala:14:57: Cannot prove that (Int, Element[_$1]) forSome { type _$1 } <:< (T, U).
[error] val output = input.map(e => e._1 -> makeList(e._1)).toMap
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 1 s, completed Jun 27, 2019, 2:38:14 PM
It appears that the problem is related to the forSome { type _$1 }
, as otherwise it should match. When I first tried to reproduce it, I used List
instead of Element
and it compiled. It appears that the different is that List
is declared as List[+T]
and the +
is important here.
Element
is from a third party library, so changing it is difficult.
What is the problem that I am running into here, and is there a simple way to fix it?
Scala version: 2.12.8
Scala gets fickle about type inference sometimes when you're doing things with existentials (which is what Element[_]
is). A quick explicit type signature will fix that right up.
val output = input.map(e => e._1 -> makeList(e._1)).toMap[Int, Element[_]]
All you're doing is telling the compiler what types you want for the keys and values. The reasons why it can't infer this are long and complicated, but as a general rule once you start throwing underscores in your types, you're going to lose some inference capabilities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With