Make Compile Fail on Non-Exhaustive Match in SBT
Asked Answered
B

4

24

Let's say that I have a trait, Parent, with one child, Child.

scala> sealed trait Parent
defined trait Parent

scala> case object Boy extends Parent
defined module Boy

I write a function that pattern matches on the sealed trait. My f function is total since there's only a single Parent instance.

scala> def f(p: Parent): Boolean = p match { 
     |   case Boy => true
     | }
f: (p: Parent)Boolean

Then, 2 months later, I decide to add a Girl child of Parent.

scala> case object Girl extends Parent
defined module Girl

And then re-write the f method since we're using REPL.

scala> def f(p: Parent): Boolean = p match { 
     |   case Boy => true
     | }
<console>:10: warning: match may not be exhaustive.
It would fail on the following input: Girl
       def f(p: Parent): Boolean = p match { 
                                   ^
f: (p: Parent)Boolean

If I were to encounter a non-exhaustive match, then I'd get a compile-time warning (as we see here).

However, how can I make the compilation fail on a non-exhaustive match?

Becki answered 4/2, 2015 at 17:13 Comment(0)
B
13

You can add -Xfatal-warnings to Scalac's options. That way any warning will be treated as an error.

In sbt, you can achieve that with:

scalacOptions += "-Xfatal-warnings"
Braga answered 4/2, 2015 at 17:16 Comment(5)
This technically answers the question, but it's often not a viable solution. I'd personally be interested in seeing answers that don't require failing on all warnings, even if they're messier.Cutpurse
@TravisBrown: Short of writing your own compiler plugin or SBT plugin, this is the only solution available.Braga
@TravisBrown, why is it often not a "viable" solution?Becki
@KevinMeredith When you're working on a project that has lots of warnings that you don't care about.Cutpurse
@Kim Stebel : old school but works: redirect the output to a file and look for the warning. In Jenkins you can make the build fail when it finds certain patterns in the log file.Scrappy
R
10

Since scalac 2.13.2 there's a fairly granular control of warnings. To get what OP asks:

scalacOptions += "-Wconf:cat=other-match-analysis:error"

Detailed howto by Lukas Rytz.

Relinquish answered 14/3, 2021 at 9:43 Comment(2)
Also the scala compiler option -Ypatmat-exhaust-depth can be useful, more info at docs.scala-lang.org/overviews/compiler-options/index.htmlPhonometer
Note: This was also backported to Scala 2.12.13+Ellsworthellwood
I
1

A compiler flag for Sbt and Scala 3 :

scalacOptions += "-Ycheck-all-patmat"

Many flags for Scala 2 do not work with Scala 3.

migration notes Scala 2 -> 3

more on Scala 3 compiler flags

Irenairene answered 22/9, 2023 at 11:20 Comment(0)
H
-7

Perhaps you could put in a default case to catch post-defined elements and bind it to a partial function which you can manage separately. Then the partial will act as a "default handler".

  sealed trait Animal
  case class Dog(name: String) extends Animal
  case class Cat(name: String) extends Animal

  val t: Animal = Dog("fido")

  // updates when the trait updates
  val partial = PartialFunction[Animal, Unit] {
    case Dog(_) => println("default dog")
    case Cat(_) => println("default cat")
    case _ => throw new RuntimeException("Broken")
  }

  // matches that may be out of date refer to it
  t match {
    case Dog(_) => println("specific dog")
    case t => partial(t)
  }

Or perhaps you can just use PartialFunctions all the way through and chain them together.

Hersh answered 4/2, 2015 at 20:16 Comment(3)
This solution brings a lot for boilerplate into codebase. Moreover, OP asks about SBT options to achieve this.Cuvette
Strange to comment so long after the question, but with 3 years of hindsight -- his problem is that he chose pattern matching in the first place. If he used something like a type class he could get the compiler failure he wants, and probably with less code.Hersh
Sorry to comment again after such a long time. Could you extrapolate on the type class approach? I'm having a similar issue here.Locomotion

© 2022 - 2024 — McMap. All rights reserved.