Suppose Lofty is a sealed trait and Earthy is one of its case classes. In a match such as this:
loftyItem match {
...
case e @ Earthy(x,y,z) => { foo(e) }
...
}
where foo expects an Earthy as argument, the compiler melts down because e is inferred only to be of type Lofty. I can work around this, but it doesn't fit my model of how things ought to be. (I'm working with Scala 2.13.5.) Can someone explain why the compiler's behavior makes sense, and make me happy with Scala again?
In response to comments, let me be more precise:
object QTest {
trait Ethereal
case class Lofty[A <: Ethereal](val slotMaybe: Option[A]) {
}
class Earthy(val field: Int) extends Ethereal
object Earthy {
def apply(fx: Int): Earthy = {
new Earthy(fx)
}
def unapply(x: Ethereal): Option[Int] = x match {
case y: Earthy => Some(y.field)
case _ => None
}
}
def testReally(just: Lofty[Ethereal]):
Lofty[Earthy] = {
just.slotMaybe match {
case Some(c) => c match {
case cnfC @ Earthy(i) => {
just.copy(slotMaybe = Some(cnfC))
}
case _ => throw new RuntimeException("oops")
}
case _ => throw new RuntimeException("oops")
}
}
}
Compiling this produces the error:
QTest.scala:25: error: type mismatch;
found : QTest.Ethereal
required: QTest.Earthy
just.copy(slotMaybe = Some(cnfC))
I obviously jumped to a conclusion, but the full example seems to have the same issue. Why does the compiler infer type Ethereal for cnfC instead of Earthy? Even if the compiler gets the type right for most uses of @, why does it get it wrong here?