I've got a case class hierarchy to encode some request and processing errors:
sealed trait OpError
sealed trait RequestErrorType
sealed trait ProcessingErrorType
final case class InvalidEndpoint(reason: String) extends RequestErrorType
final case class InvalidParameters(reason: String) extends RequestErrorType
final case class InvalidFormat(response: String) extends ProcessingErrorType
final case class EntityNotFound(id: Long) extends ProcessingErrorType
final case class RequestError(errorType: RequestErrorType) extends OpError
final case class ProcessingError(errorType: ProcessingErrorType) extends OpError
If I write a simple match across all patterns:
def printMatches(error: OpError): Unit = error match {
case RequestError(InvalidEndpoint(reason)) => //print something
case RequestError(InvalidParameters(reason)) => //print something
case ProcessingError(InvalidFormat(format)) => //print something
case ProcessingError(EntityNotFound(entityId)) => //print something
}
the compiler gives me a warning about missing match:
match may not be exhaustive.
It would fail on the following input: ProcessingError(_)
def printMatches(error: OpError): Unit = error match {
But ProcessingError takes in a ProcessingErrorType with only two extensions: InvalidFormat and EntityNotFound, both which are accounted for in the pattern match. What am I missing?
Even more curious is that if I change the parameter type of InvalidParameters or InvalidEndpoint to a String*, I don't get the error:
final case class InvalidParameters(reason: String*) extends RequestErrorType
Any ideas?
This is a confirmed bug. I filed a bug report for this and it has been since fixed for Scala 2.12.0-M4.
Very interesting! Unfortunately, I haven't found an answer. I've been revolving around http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#constructor-patterns but I haven't really found a valid explanation for what's going on.
Here's a simpler demo (hope you don't mind):
sealed abstract class ClassOne
case class ClassOneImpl() extends ClassOne
sealed abstract class ClassTwo()
case class ClassTwoImpl() extends ClassTwo
sealed abstract class Foo
case class FooOne(x: ClassOne) extends Foo
case class FooTwo(x: ClassTwo) extends Foo
def printMatches(st: Foo): Unit = st match {
case FooOne(ClassOneImpl()) => println()
case FooTwo(ClassTwoImpl()) => println()
}
I've observed that each of the following two modifications removes the warning:
1) Changing FooOne
and FooTwo
signatures so that instead of taking ClassOne
and ClassTwo
they take ClassOneImpl
and ClassTwoImpl
2) Removing FooOne
or FooTwo
so that there's only one case class extending Foo
(which leads to only one case in pattern matching).
Perhaps we could submit an issue and see what they say?
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