Patterns under irrefutable extractors are fixed

The reason that:

    sealed trait May[+A]
    final case class Just[+A](value: A) extends May[A]
    final case class Nada()             extends May[Nothing]

    object Possibly {
      def unapply[A](may: May[A]): Some[May[A]] = Some(may)
    }

    def usingMay[A](may: May[A]) = may match { // missing Nada case
      case Possibly(Just(a)) => a
    }

... also reports "Just" in addition to "Nada" is that the compiler
doesn't know under what conditions the Possibly extractor returns Nada
(which is the root of the unhandled case) so it gives you both the
input's possible types: Just and Nada.  Like before (with the "are
custom extractors idempotent") I think `Some[may.type]` fixes that, but
noone writes that.
This commit is contained in:
Dale Wijnand 2020-11-11 17:01:22 +00:00
parent a8d3741fb7
commit 855b2a8d8e
2 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,31 @@
t10502.scala:7: warning: match may not be exhaustive.
It would fail on the following inputs: None, Some(_)
def single(opt: Option[String]) = opt match { // missing None case
^
t10502.scala:10: warning: match may not be exhaustive.
It would fail on the following inputs: None, Some(_)
def nested(opt: Option[String]) = opt match { // missing None case
^
t10502.scala:13: warning: match may not be exhaustive.
It would fail on the following inputs: None, Some(_)
def nested2(opt: Option[String]) = opt match { // missing None case
^
t10502.scala:22: warning: match may not be exhaustive.
def foo(foo: Foo) = foo match { // missing None case
^
t10502.scala:32: warning: match may not be exhaustive.
def bar(bar: Bar) = bar match { // missing None case
^
t10502.scala:49: warning: match may not be exhaustive.
def length(str: String) = str match { // missing non-0 case
^
t10502.scala:62: warning: match may not be exhaustive.
def nestedUnderIrrefutable(any: Any) = any match { // missing non-int case
^
t10502.scala:75: warning: match may not be exhaustive.
It would fail on the following inputs: Just(_), Nada()
def usingMay[A](may: May[A]) = may match { // missing Nada case
^
error: No warnings can be incurred under -Werror.
8 warnings
1 error

View File

@ -0,0 +1,78 @@
// scalac: -Werror -Xlint:strict-unsealed-patmat
object Bug {
object Perhaps {
def unapply[A](oa: Option[A]): Some[Option[A]] = Some(oa)
}
def single(opt: Option[String]) = opt match { // missing None case
case Perhaps(Some(s)) => s
}
def nested(opt: Option[String]) = opt match { // missing None case
case Perhaps(Perhaps(Some(s))) => s
}
def nested2(opt: Option[String]) = opt match { // missing None case
case Perhaps(Perhaps(Perhaps(Some(s)))) => s
}
class Foo(val str: Option[String])
object Foo {
def unapply(foo: Foo): Some[Option[String]] = Some(foo.str)
}
def foo(foo: Foo) = foo match { // missing None case
case Foo(Some(s)) => s
}
class Bar(val str: Option[String], val ing: Option[String])
object Bar {
def unapply(bar: Bar): Some[(Option[String], Option[String])] = Some((bar.str, bar.ing))
}
def bar(bar: Bar) = bar match { // missing None case
case Bar(Some(s), _) => s
}
def list(list: List[Option[String]]) = list match {
case Perhaps(Some(s)) :: _ => s
case Perhaps(None ) :: _ => "<none>"
case Nil => "<nil>"
} // was: warning: match may not be exhaustive.
// It would fail on the following input: List(_)
object Length {
def unapply(str: String): Some[Int] = Some(str.length)
}
def length(str: String) = str match { // missing non-0 case
case Length(0) => "empty!"
}
object ToStr {
def unapply(any: Any): Some[String] = Some(any.toString)
}
object ToInt {
def unapply(str: String): Option[Int] = str.toIntOption
}
def nestedUnderIrrefutable(any: Any) = any match { // missing non-int case
case ToStr(ToInt(n)) => n
}
sealed trait May[+A]
final case class Just[+A](value: A) extends May[A]
final case class Nada() extends May[Nothing]
object Possibly {
def unapply[A](may: May[A]): Some[May[A]] = Some(may)
}
def usingMay[A](may: May[A]) = may match { // missing Nada case
case Possibly(Just(a)) => a
}
}