Skip to content

Fix wrong exhaustive check with sequence wildcard on case class with custom unapply#24260

Merged
noti0na1 merged 2 commits into
scala:mainfrom
zielinsky:i23459v2
Mar 3, 2026
Merged

Fix wrong exhaustive check with sequence wildcard on case class with custom unapply#24260
noti0na1 merged 2 commits into
scala:mainfrom
zielinsky:i23459v2

Conversation

@zielinsky

@zielinsky zielinsky commented Oct 26, 2025

Copy link
Copy Markdown
Member

Fixes #23459

Based on Scala Lang Spec

@zielinsky zielinsky force-pushed the i23459v2 branch 3 times, most recently from 7dabd1e to 445195f Compare October 28, 2025 11:25
@zielinsky zielinsky marked this pull request as ready for review January 14, 2026 10:30
@zielinsky zielinsky requested a review from noti0na1 January 14, 2026 10:30
Comment thread tests/warn/i23459.scala Outdated

@main def run(): Unit =
Test() match
case Test(x*) => println(x) // warn

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't we disallow this sequence pattern, as there is no unapplySeq in object Test?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hi, thanks, yes!!
I agree this aligns with the spec, and I've updated the PR to emit an error instead of a warning, but I'm a bit concerned about potential backward compatibility for code that may have relied on this being silently accepted.

@noti0na1

noti0na1 commented Jan 26, 2026

Copy link
Copy Markdown
Member

While testing some other examples, I'm surprised that unapplySeq does not work on a companion object of a case class:

case class Test()

object Test:
  def unapplySeq(t: Test): Option[Seq[Int]] = Some(Seq(1, 2))

object TTest:
  def unapplySeq(t: Test): Option[Seq[Int]] = Some(Seq(1, 2))

@main def run(): Unit =
  Test() match
    case Test(x*) => () // error: Wrong number of argument patterns for Test; expected: ()
  Test() match
    case TTest(x*) => ()

@zielinsky zielinsky force-pushed the i23459v2 branch 2 times, most recently from 4868a7c to 484c1e5 Compare February 16, 2026 21:58
@zielinsky

zielinsky commented Feb 16, 2026

Copy link
Copy Markdown
Member Author

While testing some other examples, I'm surprised that unapplySeq does not work on a companion object of a case class:

case class Test()

object Test:
  def unapplySeq(t: Test): Option[Seq[Int]] = Some(Seq(1, 2))

object TTest:
  def unapplySeq(t: Test): Option[Seq[Int]] = Some(Seq(1, 2))

@main def run(): Unit =
  Test() match
    case Test(x*) => () // error: Wrong number of argument patterns for Test; expected: ()
  Test() match
    case TTest(x*) => ()

@noti0na1
This happens because for case class Test(), the compiler auto-generates unapply, and trySelectUnapply always tries unapply before unapplySeq. Right now, it reports "Sequence wildcard pattern is not allowed for unapply, only unapplySeq is allowed", which (I think) better explains why the pattern is rejected.

@Gedochao

Gedochao commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Bump @noti0na1

Comment thread tests/neg/i23459b.check Outdated
@zielinsky zielinsky requested a review from noti0na1 March 3, 2026 20:29
@noti0na1 noti0na1 merged commit 1311fb5 into scala:main Mar 3, 2026
104 of 105 checks passed
@WojciechMazur WojciechMazur added this to the 3.8.4 milestone Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wrong exhaustive check with sequence wildcard on case class with custom unapply

5 participants