bug icon indicating copy to clipboard operation
bug copied to clipboard

Imprecise warning messages for non-exhaustive cases regarding List

Open Medowhill opened this issue 2 years ago • 2 comments

Reproduction steps

Scala version: 2.13.8

scala> List() match { case Nil => ; case List(_) => }
           ^
       warning: match may not be exhaustive.
       It would fail on the following input: List(_)

Problem

I found that Scala 2's warning messages for non-exhaustive cases regarding List are a bit imprecise. On the other hand, Scala 3 gives better messages:

scala> List() match { case Nil => ; case List(_) => }
1 warning found
-- [E029] Pattern Match Exhaustivity Warning: ----------------------------------
1 |List() match { case Nil => ; case List(_) => }
  |^^^^^^
  |match may not be exhaustive.
  |
  |It would fail on pattern case: List(_, _, _*)

I checked Scala 2's MatchAnalysis implementation, and it seems to simply ignore unapplySeq extractors in general (and it handles only List() as a special case). Although it wouldn't be possible to check exhaustivity for every unapplySeq extractor, checking at least List would be great, as Scala 3 already does so. Is there any plan to work on this issue?

Medowhill avatar Mar 31 '22 11:03 Medowhill

@dwijnand this doesn't seem to be a duplicate of any existing ticket I could find. any insight here? I'm curious if it's just a problem in the message generation, or whether it's exposing some more fundamental underlying limitation in the exhaustivity checker.

SethTisue avatar Mar 31 '22 14:03 SethTisue

No, it's just a problem in the message generation, or rather the counter-example generation. This can be our ticket for Scala 2's match analysis not being great at counter-examples based on unapplySeq arity.

dwijnand avatar Apr 06 '22 08:04 dwijnand

Another example (unapply not unapplySeq):

sealed trait A
case object A1 extends A
case object A2 extends A
sealed trait T { def a: A }
object T { def unapply(t: T): Some[A] = Some(t.a) }
case class T1(x: Int) extends T { def a = A1 }
case class T2(x: Int) extends T { def a = A2 }

object Test {
  def m(t: T) = t match {
    case T(A1) => 0
    // case T(A2) => 1
  }
}

Exhaustivity can correctly identify the (in)completeness of the match, but the counter-examples in the warning message are misleading.

➜ sandbox sc Test.scala
Test.scala:10: warning: match may not be exhaustive.
It would fail on the following inputs: T1(_), T2(_)
  def m(t: T) = t match {
                ^
1 warning

lrytz avatar Jan 11 '23 14:01 lrytz