Skip to content

Commit

Permalink
Implement -Xnon-strict-patmat-analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Oct 9, 2020
1 parent 789c827 commit b868750
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -168,6 +168,7 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
def isAtLeastJunit = isTruthy || XmixinForceForwarders.value == "junit"
}

val nonStrictPatmatAnalysis = BooleanSetting("-Xnon-strict-patmat-analysis", "Disable strict exhaustivity analysis, which assumes guards are false and refutable extractors don't match")
val noUnsealedPatmatAnalysis = BooleanSetting("-Xno-unsealed-patmat-analysis", "Pattern match on an unsealed class without a catch-all.")

// XML parsing options
Expand Down
Expand Up @@ -521,14 +521,15 @@ trait MatchAnalysis extends MatchApproximation {
// - back off (to avoid crying exhaustive too often) in unhandled cases
val start = if (StatisticsStatics.areSomeColdStatsEnabled) statistics.startTimer(statistics.patmatAnaExhaust) else null
var backoff = false
val strict = !settings.nonStrictPatmatAnalysis.value

val approx = new TreeMakersToProps(prevBinder)
val symbolicCases = approx.approximateMatch(cases, approx.onUnknown { tm =>
approx.fullRewrite.applyOrElse[TreeMaker, Prop](tm, {
case BodyTreeMaker(_, _) => True // irrelevant -- will be discarded by symbolCase later
case ExtractorTreeMaker(_, _, _)
| ProductExtractorTreeMaker(_, _)
| GuardTreeMaker(_) =>
| GuardTreeMaker(_) if strict =>
False
case _ =>
debug.patmat("backing off due to "+ tm)
Expand Down Expand Up @@ -767,6 +768,8 @@ trait MatchAnalysis extends MatchApproximation {
// so, naively, you might try to construct a counter example like _ :: Nil(_ :: _, _ :: _),
// since we didn't realize the tail of the outer cons was a Nil)
def modelToCounterExample(scrutVar: Var)(varAssignment: Map[Var, (Seq[Const], Seq[Const])]): Option[CounterExample] = {
val strict = !settings.nonStrictPatmatAnalysis.value

// chop a path into a list of symbols
def chop(path: Tree): List[Symbol] = path match {
case Ident(_) => List(path.symbol)
Expand Down Expand Up @@ -895,8 +898,8 @@ trait MatchAnalysis extends MatchApproximation {
// if uniqueEqualTo contains more than one symbol of the same domain
// then we can safely ignore these counter examples since we will eventually encounter
// both counter examples separately
case _ if inSameDomain =>
Some(WildcardExample)
// ... in strict mode, consider variable assignment as a wild counter-example
case _ if inSameDomain => if (strict) Some(WildcardExample) else None

// not a valid counter-example, possibly since we have a definite type but there was a field mismatch
// TODO: improve reasoning -- in the mean time, a false negative is better than an annoying false positive
Expand Down
42 changes: 42 additions & 0 deletions test/files/pos/t5365-nonStrict.scala
@@ -0,0 +1,42 @@
// scalac: -Werror -Xnon-strict-patmat-analysis
//
// copy of neg/t5365.scala, which under -Xnon-strict-patmat-analysis gives no warnings
class C {
def nonExhautiveIfWeAssumeGuardsTrueOrFalse(x: Option[Int]): Int = x match {
case Some(n) if n % 2 == 0 => n
}

def nonExhautiveIfWeAssumeGuardsFalse(x: Option[Int]): Int = x match {
case Some(n) if n % 2 == 0 => n
case None => 0
}

def inverseGuards(x: Option[Int]): Int = x match {
case Some(n) if n > 0 => n
case Some(n) if n <= 0 => ???
case None => 0
}

def extractor(x: Option[Int]) = x match {
case Some(Extractor(_)) =>
}
def repeatedExtractor(x: Option[Int]) = x match {
case Some(RepeatedExtractor(_)) =>
}
def extractorStrict(x: Option[Int]) = x match {
case Some(Extractor(_)) =>
case None =>
}
def repeatedExtractorStrict(x: Option[Int]) = x match {
case Some(RepeatedExtractor(_)) =>
case None =>
}
}

object Extractor {
def unapply(a: Any): Option[Any] = None
}

object RepeatedExtractor {
def unapplySeq(a: Any): Option[Seq[Any]] = None
}

0 comments on commit b868750

Please sign in to comment.