Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complementing irrefutable unapplySeq aren't recognized as exhaustive #12252

Open
martijnhoekstra opened this issue Nov 28, 2020 · 2 comments
Open
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) patmat
Milestone

Comments

@martijnhoekstra
Copy link

reproduction steps

using any version of Scala

object SeqExtractor {
  def unapplySeq(x: Int): Some[List[Int]] = Some(List(1))
}

1 match {
 case SeqExtractor() => "zero"
 case SeqExtractor(_) => "one"
 case SeqExtractor(_, _, _*) => "two or more"
}

problem

SeqExtractor is irrefutable, and the three cases together are exhaustive, but we fail to recognize that.

note

Matching on List can work around that by matching on Cons or Nil exhaustively with

List(1) match {
case Nil => 0 // or List() due to rewrite
case head :: Nil => 1
case head :: second :: tail => 2
}

Spun out of #12240

@hochgi
Copy link

hochgi commented Apr 7, 2022

I think it is also the case for regular unapply.
In my example, I was dealing with a Json AST, (sealed trait Json), and had several cases where the treatment for non-Obj was short, and for object longer.
So I added an extractor object for cosmetic reasons:

object NonObj {
  def unapply(json: Json): Option[Json] = json match {
    case _: Json.Obj => None
    case notAnObject => Some(notAnObject)
  }
}

and used it as:

def foo(json: Json): Either[Throwable, SomeClass] = json match {
  case NonObj(json) => Left(MismatchError(s"$json was not '{…}'"))
  case j: Json.Obj =>
    // very
    // long
    // body
    //
}

and was surprised to see warnings like:

[warn] /home/hochgi/dev/…/src/main/scala/com/hochgi/some/path/SomeClass.scala:123:64: match may not be exhaustive.
[warn] It would fail on the following inputs: Bool(_), ByteNum(_), DoubleNum(_), FloatNum(_), IntNum(_), LongNum(_), Null, ShortNum(_), Str(_), Undefined, _
[warn]     override def foo(json: Json): Either[Throwable, SomeClass] = json match {
[warn]                                                                  ^

@som-snytt
Copy link

@hochgi AFAIK it doesn't peer into your extractor to see what it handles. Pattern matching is mysterious, so your question would be helpful on the forum. I don't know where these nuances are described in docs; my sense is that they try to make it "just work", with regard to warnings.

This ticket is about something entirely different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) patmat
Projects
None yet
Development

No branches or pull requests

5 participants