Search code examples
scalapattern-matchingtype-parameteralgebraic-data-types

Unable to match a parameterized type with a concrete type after pattern-matching


Using scala 2.12.8 this would not compile without a cast:

trait Content
case object A extends Content
case class B(i: Int) extends Content

def asList[C <: Content](content: C): List[C] = content match {
  case A => List(A) // compiles
  case b: B => List(b) // does not compile
}
type mismatch;
 found   : b.type (with underlying type Playground.this.B)
 required: C

Here's a Scastie link to the problem: https://scastie.scala-lang.org/JIziYOYNTwKoZpdCIPCvdQ

Why is working for the case object and not for the case class? How can I make it work for the case class?

EDIT

The first answers made me realize I oversimplified my problem, here's an updated version :

sealed trait Content
case object A extends Content
final case class B(i: Int) extends Content

sealed trait Container[+C <: Content]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]

object Container {
  def apply[C <: Content](content: C): Container[C] = content match {
    case A => ContainerA(A) // compiles
    case b: B => ContainerB(b) // does not compile
  }
}

Scastie link: https://scastie.scala-lang.org/TDlJM5SYSwGl2gmQPvKEXQ

C cannot be a subtype of B since B is final.


Solution

  • C cannot be a subtype of B since B is final.

    Wrong!

    Singleton types of B instances are subtypes of B:

    val b = B(0)
    val container: Container[b.type] = Container[b.type](b)
    

    Since ContainerB doesn't extend Container[b.type], it can't be returned by the last line. And it can't be changed so that it does;

    case class ContainerB(content: B) extends Container[content.type]
    

    is not legal in Scala.

    Null is also a subtype of B and you can create a similar example. And so are refinement types like B { type T = Int }.

    Other subtypes which are probably irrelevant because they don't have instances: Nothing, compound types like B with Iterable[Int]...