Skip to content

Missing exhaustivity when pattern matching on nested case classes #13003

Closed
@martingd

Description

@martingd

When pattern matching on a nested case class pattern like, case One(Two(Some(...))) the Scala 3 compiler does not detect the match as being non-exhaustive – unless option -Ycheck-all-patmat is given.

Compiler version

I have tested on compiler version 3.0.2-RC1-bin-20210701-9f97b0b-NIGHTLY (as well as on 3.0.0 where even more cases go undetected.)

Minimized code

Given this code…

case class One(two: Two)
case class Two(o: Option[Int])

def matchOneTwo(one: One) = one match
    case One(Two(Some(i))) => "match!"

def matchTwo(two: Two) = two match
    case Two(Some(i)) => "match!"

def matchOO(oo: Option[Option[Int]]) = oo match
    case Some(Some(i)) => "match!"

def matchOOO(ooo: Option[Option[Option[Int]]]) = ooo match
    case Some(Some(Some(i))) => "match!"

…the compiler only emits warnings about non-exhaustive matches for matchTwo(), matchOO(), and matchOOO() but not for matchOneTwo() – unless compiler option -Ycheck-all-patmat is given.

Output

Without option -Ycheck-all-patmat the output is:

-- [E029] Pattern Match Exhaustivity Warning: /path/to/Example.scala:7:25 
7 |def matchTwo(two: Two) = two match
  |                         ^^^
  |                         match may not be exhaustive.
  |
  |                         It would fail on pattern case: Two(None)
-- [E029] Pattern Match Exhaustivity Warning: /path/to/Example.scala:10:39 
10 |def matchOO(oo: Option[Option[Int]]) = oo match
   |                                       ^^
   |                         match may not be exhaustive.
   |
   |                         It would fail on pattern case: None, Some(None)
-- [E029] Pattern Match Exhaustivity Warning: /path/to/Example.scala:13:49 
13 |def matchOOO(ooo: Option[Option[Option[Int]]]) = ooo match
   |                                                 ^^^
   |       match may not be exhaustive.
   |
   |       It would fail on pattern case: None, Some(None), Some(Some(None))
three warnings found
three warnings found

Adding compiler option -Ycheck-all-patmat causes the missing case to be detected:

4 |def matchOneTwo(one: One) = one match
  |                            ^^^
  |                            match may not be exhaustive.
  |
  |                            It would fail on pattern case: One(Two(None))
-- [E029] Pattern Match Exhaustivity Warning: /path/to/Example.scala:7:25 

However, from the description of the compiler option:

-Ycheck-all-patmat          Check exhaustivity and redundancy of all pattern
                            matching (used for testing the algorithm).

I would not expect this option to be one to use “in production” – I might be wrong here.

Expectation

I would expect the compiler to detect all four cases without the use of compiler option -Ycheck-all-patmat.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions