Skip to content

Add test for t12237 #11528

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

Merged
merged 1 commit into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/patmat/t12237.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
21: Pattern Match Exhaustivity: Root, PathAndQuery./(_, _), PathAndQuery.===(_, _), PathAndQuery.:&(_, PathAndQuery.===(_, _)), PathAndQuery.+?(_, PathAndQuery.===(_, _))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right expected result? What does PathAndQuery./(_, _) mean? Because the first case is matching values that are PathAndQuery./. Similarly PathAndQuery.:&(_, PathAndQuery.===(_, _)) and PathAndQuery.+?(_, PathAndQuery.===(_, _)). I don't understand what the check file is asserting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's the correct expect file, PathAndQuery./(_, _) means that pattern is not exhaustive. The test is to defend against compiler hangs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PathAndQuery./(_, _) means that pattern is not exhaustive.

I see. (Perhaps reporting PathAndQuery.:&(_, _) and PathAndQuery.+?(_, _) might be more uniform?)

I guess the Scala 3 checker doesn't try to give good counter-examples like Scala 2, which tries to do something like Root / "page" / x forSome x != "1"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would like to have refined counter-examples as in Scala 2. However, we could not figure out how to make it principled. For example, given the following example:

object Even {
  def unapply(x: Int): Option[Int] = ???
}

class Test {
  def foo(x: Option[Option[Int]]): Unit =
    x match {
      case Some(Some(5)) =>
      case Some(Some(Even(10))) =>
      case None =>
    }
}

It's unclear how to handle extractors in the warnings. Even if it's possible to be more principled, there's the worry that the message gets messy, thus difficult to read.

Meanwhile, even with refined counter-examples, users still need to check the existing patterns. Due to the considerations, we only show general counter examples.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Scala 2's counter-example generation definitely doesn't handle extractors: it's all field based (for case classes) so it has no chance - it needs to be revisited. But it does a good job for case classes I say. It seems to be to be a good thing to generalise case class's unapply/extraction with the "product match" extractors, but it seems like discarding that knowledge for counter-example generation is lossy and thus a shame.

26 changes: 26 additions & 0 deletions tests/patmat/t12237.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
sealed trait PathAndQuery
sealed trait Path extends PathAndQuery
sealed trait Query extends PathAndQuery

object PathAndQuery {
case object Root extends Path
case class /(prev: Path, value: String) extends Path
case class ===(k: String, v: String) extends Query
case class :&(prev: Query, next:(===)) extends Query
case class +?(path: Path, next:(===)) extends Query
}

import PathAndQuery._

class Test {
val path = /(/(Root, "page"), "1")
val q1 = ===("k1", "v1")
val q2 = ===("k2", "v2")
val pq = :&(+?(path, q1), q2)

(pq: PathAndQuery) match {
case Root / "page" / "1" => println("match 1")
case Root / "page" / "1" +? ("k1" === "v1") => println("match 2")
case Root / "page" / "1" +? ("k1" === "v1") :& ("k2" === "v2") => println("match 3")
}
}