-
Notifications
You must be signed in to change notification settings - Fork 3.1k
SI-5365 Enable exhaustivity analysis of matches with guards #4929
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
Conversation
|
TODO:
|
|
s/exhautivity/exhaustivity ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This warning message is imprecise, it should technically say Some(x forSome x not in Extractor(x)).
|
I just found another hole in our exhaustivity checking. The constructor pattern This root cause of this was fixed recently as #4862 (which isn't merged yet to the 2.12.x branch). |
Rather than disabling the analysis altogether, rewrite
guard to `true` (by default) or to `false` under a new
compiler option.
The default option errs on the side of avoiding spurious
warnings where the guard writer knows better. However,
there was a convincing argument made in the ticket that
in these cases it would not be to onerous to require
the code to be rewritten from
case P if g1 =>
case P if g2 =>
to:
case P if g1 =>
case P =>
Or to:
(scrut: @unchecked) match {
case P if g1 =>
case P if g2 =>
So perhaps we can turn on the strict version by
default, after running against the community build
as a sanity check.
Extractor patterns had the same limitation as guards.
This commit also enables the analysis for them in the
same way as done for guards. However, this still not
done for `unapplySeq` extractors, as the counter example
generator can't handle these yet.
|
I understand this still doesn't issue a warning if the type of trait Z
final case class Q(i: Int) extends Z
def f(z: Z) = z match {
case Q(_) =>
}Would it be possible to get a warning in cases like this too? I realize, that this is even more strict than the Also, after playing a bit more with this code, the warnings for extractors seem to behave somewhat surprisingly. For example, code like this compiles without any warnings: sealed trait T
final case class C(i: Int) extends T
final case class D(i: Int) extends T
object X {
def unapply(t: T): Option[Int] = None
}
def g(t: T): Unit = t match {
case X(_) =>
}However, if I put in another case, thus increasing (or at least not decreasing) the exhaustiveness of the match, I get an (expected) warning: def g(t: T): Unit = t match {
case X(_) =>
case C(_) =>
}To be clear, the (to me) surprising thing is the absence of the warning in the first case. Is this behavior intentional? |
|
Let's take another look at this after M5. Scheduling for RC1. |
|
I don't have time to push this one forward right now, so I'm going to close the PR for now. |
|
I’d like to pick this up, if it’s ok with @retronym. My own opinions: it’d be nice to make “false” the default (@adriaanm – how likely is that?). Also, we should warn whenever the checker gives up (which I think would cover @durban’s |
|
Great! I can be convinced of whatever strategy results in the best experience for the majority of Scala programmers. |
| approx.fullRewrite.applyOrElse[TreeMaker, Prop](tm, { | ||
| case BodyTreeMaker(_, _) => True // irrelevant -- will be discarded by symbolCase later | ||
| case GuardTreeMaker(_) => if (strict) False else True | ||
| case ExtractorTreeMaker(extractor, _, _) if extractor.symbol.name != nme.unapplySeq => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@retronym I thought the guard here was because of SI-9567 (fixed in #4862, which seems to have been merged into 2.12.x at this point). However, removing it in order to get the correct repeatedExtractor warnings causes other tests to fail (e.g., run/patmatnew.scala:58, which is an exhaustive match on List[Int]).
Wondering if you think there’s a middle ground that can be achieved, or if the repeatedExtractor warnings are a bit too ambitious (at least for me).
|
We should at least let this be available behind a compiler flag. Without this people will avoid using guards so they can be sure of the exhaustive warning/compile error. |
Rather than disabling the analysis altogether, rewrite
guard to
true(by default) or tofalseunder a newcompiler option.
The default option errs on the side of avoiding spurious
warnings where the guard writer knows better. However,
there was a convincing argument made in the ticket that
in these cases it would not be to onerous to require
the code to be rewritten from
to:
Or to:
So perhaps we can turn on the strict version by
default, after running against the community build
as a sanity check.
Extractor patterns had the same limitation as guards.
This commit also enables the analysis for them.