Skip to content
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

Switch off exhaustivity warnings for unsealed types (by default) #9299

Merged
merged 1 commit into from Nov 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions project/ScalaOptionParser.scala
Expand Up @@ -83,7 +83,7 @@ object ScalaOptionParser {

// TODO retrieve these data programmatically, ala https://github.com/scala/scala-tool-support/blob/master/bash-completion/src/main/scala/BashCompletion.scala
private def booleanSettingNames = List("-X", "-Xasync", "-Xcheckinit", "-Xdev", "-Xdisable-assertions", "-Xexperimental", "-Xfatal-warnings", "-Xlog-free-terms", "-Xlog-free-types", "-Xlog-implicit-conversions", "-Xlog-implicits", "-Xlog-reflective-calls",
"-Xno-forwarders", "-Xno-patmat-analysis", "-Xno-unsealed-patmat-analysis", "-Xnon-strict-patmat-analysis", "-Xprint-pos", "-Xprint-types", "-Xprompt", "-Xresident", "-Xshow-phases", "-Xverify", "-Y",
"-Xno-forwarders", "-Xno-patmat-analysis", "-Xnon-strict-patmat-analysis", "-Xprint-pos", "-Xprint-types", "-Xprompt", "-Xresident", "-Xshow-phases", "-Xverify", "-Y",
"-Ybreak-cycles", "-Ydebug", "-Ycompact-trees", "-YdisableFlatCpCaching", "-Ydoc-debug",
"-Yide-debug",
"-Yissue-debug", "-Ylog-classpath", "-Ymacro-debug-lite", "-Ymacro-debug-verbose", "-Ymacro-no-expand",
Expand All @@ -108,7 +108,7 @@ object ScalaOptionParser {
"-g" -> List("line", "none", "notailcails", "source", "vars"),
"-target" -> targetSettingNames)
private def multiChoiceSettingNames = Map[String, List[String]](
"-Xlint" -> List("adapted-args", "nullary-unit", "inaccessible", "nullary-override", "infer-any", "missing-interpolator", "doc-detached", "private-shadow", "type-parameter-shadow", "poly-implicit-overload", "option-implicit", "delayedinit-select", "package-object-classes", "stars-align", "constant", "unused", "eta-zero"),
"-Xlint" -> List("adapted-args", "nullary-unit", "inaccessible", "nullary-override", "infer-any", "missing-interpolator", "doc-detached", "private-shadow", "type-parameter-shadow", "poly-implicit-overload", "option-implicit", "delayedinit-select", "package-object-classes", "stars-align", "strict-unsealed-patmat", "constant", "unused", "eta-zero"),
"-language" -> List("help", "_", "dynamics", "postfixOps", "reflectiveCalls", "implicitConversions", "higherKinds", "existentials", "experimental.macros"),
"-opt" -> List("unreachable-code", "simplify-jumps", "compact-locals", "copy-propagation", "redundant-casts", "box-unbox", "nullness-tracking", "closure-invocations" , "allow-skip-core-module-init", "assume-modules-non-null", "allow-skip-class-loading", "inline", "l:none", "l:default", "l:method", "l:inline", "l:project", "l:classpath"),
"-Ywarn-unused" -> List("imports", "patvars", "privates", "locals", "explicits", "implicits", "params"),
Expand Down
3 changes: 1 addition & 2 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -168,8 +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.")
val nonStrictPatmatAnalysis = BooleanSetting("-Xnon-strict-patmat-analysis", "Disable strict exhaustivity analysis, which assumes guards are false and refutable extractors don't match")

// XML parsing options
object XxmlSettings extends MultiChoiceEnumeration {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/scala/tools/nsc/settings/Warnings.scala
Expand Up @@ -177,6 +177,7 @@ trait Warnings {
val DelayedInitSelect = LintWarning("delayedinit-select", "Selecting member of DelayedInit.")
val PackageObjectClasses = LintWarning("package-object-classes", "Class or object defined in package object.")
val StarsAlign = LintWarning("stars-align", "In a pattern, a sequence wildcard `_*` should match all of a repeated parameter.")
val StrictUnsealedPatMat = LintWarning("strict-unsealed-patmat", "Pattern match on an unsealed class without a catch-all.")
val Constant = LintWarning("constant", "Evaluation of a constant arithmetic expression resulted in an error.")
val Unused = LintWarning("unused", "Enable -Wunused:imports,privates,locals,implicits,nowarn.")
val NonlocalReturn = LintWarning("nonlocal-return", "A return statement used an exception for flow control.")
Expand Down Expand Up @@ -208,6 +209,7 @@ trait Warnings {
def warnOptionImplicit = lint contains OptionImplicit
def warnDelayedInit = lint contains DelayedInitSelect
def warnPackageObjectClasses = lint contains PackageObjectClasses
def warnStrictUnsealedPatMat = lint contains StrictUnsealedPatMat
def warnStarsAlign = lint contains StarsAlign
def warnConstant = lint contains Constant
def lintUnused = lint contains Unused
Expand Down
Expand Up @@ -514,7 +514,7 @@ trait MatchAnalysis extends MatchApproximation {

// exhaustivity

def exhaustive(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[String] = if (settings.noUnsealedPatmatAnalysis && uncheckableType(prevBinder.info)) Nil else {
def exhaustive(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[String] = if (!settings.warnStrictUnsealedPatMat && uncheckableType(prevBinder.info)) Nil else {
// customize TreeMakersToProps (which turns a tree of tree makers into a more abstract DAG of tests)
// - approximate the pattern `List()` (unapplySeq on List with empty length) as `Nil`,
// otherwise the common (xs: List[Any]) match { case List() => case x :: xs => } is deemed unexhaustive
Expand Down
13 changes: 0 additions & 13 deletions test/files/neg/patmat-seq-neg.check
@@ -1,9 +1,3 @@
patmat-seq-neg.scala:12: warning: match may not be exhaustive.
def t2: Any = 2 match {
^
patmat-seq-neg.scala:15: warning: match may not be exhaustive.
def t3: Any = 2 match {
^
patmat-seq-neg.scala:15: error: error during expansion of this match (this is a scalac bug).
The underlying error was: type mismatch;
found : scala.collection.mutable.ArrayBuffer[Int]
Expand All @@ -14,15 +8,8 @@ patmat-seq-neg.scala:18: error: error during expansion of this match (this is a
The underlying error was: value toSeq is not a member of Array[Int]
def t4: Any = 2 match {
^
patmat-seq-neg.scala:21: warning: match may not be exhaustive.
def t5: Any = 2 match {
^
patmat-seq-neg.scala:24: warning: match may not be exhaustive.
def t6: Any = 2 match {
^
patmat-seq-neg.scala:24: error: error during expansion of this match (this is a scalac bug).
The underlying error was: value drop is not a member of Array[Int]
def t6: Any = 2 match {
^
4 warnings
3 errors
21 changes: 0 additions & 21 deletions test/files/neg/t11102.check
@@ -1,34 +1,13 @@
t11102.scala:2: warning: match may not be exhaustive.
It would fail on the following input: (x: ImmutableSeq forSome x not in ImmutableCons)
def f(x: ImmutableSeq) = x match {
^
t11102.scala:5: warning: match may not be exhaustive.
It would fail on the following input: (x: MutableSeq forSome x not in MutableCons)
def f(x: MutableSeq) = x match {
^
t11102.scala:5: error: error during expansion of this match (this is a scalac bug).
The underlying error was: type mismatch;
found : Seq[MutableCons] (in scala.collection.mutable)
required: Seq[MutableCons] (in scala.collection.immutable)
def f(x: MutableSeq) = x match {
^
t11102.scala:8: warning: match may not be exhaustive.
It would fail on the following input: (x: CollectionSeq forSome x not in CollectionCons)
def f(x: CollectionSeq) = x match {
^
t11102.scala:8: error: error during expansion of this match (this is a scalac bug).
The underlying error was: type mismatch;
found : Seq[CollectionCons] (in scala.collection)
required: Seq[CollectionCons] (in scala.collection.immutable)
def f(x: CollectionSeq) = x match {
^
t11102.scala:11: warning: match may not be exhaustive.
It would fail on the following input: (x: ScalaSeq forSome x not in ScalaCons)
def f(x: ScalaSeq) = x match {
^
t11102.scala:14: warning: match may not be exhaustive.
It would fail on the following input: (x: DefaultSeq forSome x not in DefaultCons)
def f(x: DefaultSeq) = x match {
^
5 warnings
2 errors
6 changes: 1 addition & 5 deletions test/files/neg/t11746.check
@@ -1,11 +1,7 @@
t11746.scala:16: warning: match may not be exhaustive.
It would fail on the following input: (x: Try forSome x not in Failure)
private def get(a: String): Unit = Try(a) match {
^
t11746.scala:18: warning: failed to determine if e should be inlined:
The method e()Ljava/lang/Throwable; could not be found in the class java/lang/Object or any of its parents.
case Failure(e) => println(e.toString)
^
error: No warnings can be incurred under -Werror.
2 warnings
1 warning
1 error
2 changes: 1 addition & 1 deletion test/files/neg/t5365c.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings
// scalac: -Xfatal-warnings -Xlint:strict-unsealed-patmat
object C {
trait Z
final case class Q(i: Int) extends Z
Expand Down
6 changes: 1 addition & 5 deletions test/files/neg/t5898.check
Expand Up @@ -6,10 +6,6 @@ t5898.scala:10: warning: match may not be exhaustive.
It would fail on the following input: C(_)
val D(x) = t
^
t5898.scala:11: warning: match may not be exhaustive.
It would fail on the following input: (x: Any forSome x not in D)
val D(y) = (null: Any)
^
error: No warnings can be incurred under -Werror.
3 warnings
2 warnings
1 error
2 changes: 1 addition & 1 deletion test/files/neg/t7623.scala
@@ -1,4 +1,4 @@
// scalac: -Xlint:stars-align -Xfatal-warnings -Xno-unsealed-patmat-analysis
// scalac: -Xlint:stars-align -Xfatal-warnings
//


Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t8597.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings -Xno-unsealed-patmat-analysis
// scalac: -Xfatal-warnings
//
class Unchecked[C] {
def nowarn[T] = (null: Any) match { case _: Some[T] => } // warn (did not warn due to scala/bug#8597)
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t8597b.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings -Xno-unsealed-patmat-analysis
// scalac: -Xfatal-warnings
//
object Unchecked {
(null: Any) match {
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t8731.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings -Xno-unsealed-patmat-analysis
// scalac: -Xfatal-warnings
//
class C {
// not a compile-time constant due to return type
Expand Down
10 changes: 5 additions & 5 deletions test/files/neg/tailrec-4.check
@@ -1,16 +1,16 @@
tailrec-4.scala:7: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
tailrec-4.scala:6: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
@tailrec def foo: Int = foo + 1
^
tailrec-4.scala:12: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
tailrec-4.scala:11: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
@tailrec def foo: Int = foo + 1
^
tailrec-4.scala:18: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
tailrec-4.scala:17: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
@tailrec def foo: Int = foo + 1
^
tailrec-4.scala:24: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
tailrec-4.scala:23: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
@tailrec def foo: Int = foo + 1
^
tailrec-4.scala:32: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
tailrec-4.scala:31: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
@tailrec def foo: Int = foo + 1
^
5 errors
1 change: 0 additions & 1 deletion test/files/neg/tailrec-4.scala
@@ -1,4 +1,3 @@
// scalac: -Xno-unsealed-patmat-analysis
import annotation._

object Tail {
Expand Down
6 changes: 1 addition & 5 deletions test/files/neg/unchecked-refinement.check
Expand Up @@ -10,15 +10,11 @@ unchecked-refinement.scala:25: warning: a pattern match on a refinement type is
unchecked-refinement.scala:26: warning: a pattern match on a refinement type is unchecked
/* nowarn - todo */ case x: AnyRef { def size: Int } if b => x.size // this could/should do a static conformance test and not warn
^
unchecked-refinement.scala:18: warning: match may not be exhaustive.
It would fail on the following input: ??
def f3[T, U, V](x: Foo[T, U, V]) = x match {
^
unchecked-refinement.scala:24: warning: match may not be exhaustive.
It would fail on the following inputs: List(_), Nil
def f4(xs: List[Int]) = xs match {
^
warning: 1 feature warning; re-run with -feature for details
error: No warnings can be incurred under -Werror.
7 warnings
6 warnings
1 error
2 changes: 1 addition & 1 deletion test/files/neg/unchecked3.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings -Xno-unsealed-patmat-analysis
// scalac: -Xfatal-warnings
//
sealed trait A2[T1]
final class B2[T1, T2] extends A2[T1]
Expand Down
6 changes: 1 addition & 5 deletions test/files/neg/virtpatmat_unreach_select.check
@@ -1,10 +1,6 @@
virtpatmat_unreach_select.scala:12: warning: unreachable code
case WARNING.id => // unreachable
^
virtpatmat_unreach_select.scala:9: warning: match may not be exhaustive.
It would fail on the following input: (x: Int forSome x not in (id, id))
(0: Int) match {
^
error: No warnings can be incurred under -Werror.
2 warnings
1 warning
1 error
File renamed without changes.
3 changes: 0 additions & 3 deletions test/files/run/matchonstream.check
@@ -1,4 +1 @@
matchonstream.scala:2: warning: match may not be exhaustive.
LazyList.from(1) match { case LazyList(1, 2, x @_*) => println(s"It worked! (class: ${x.getClass.getSimpleName})") }
^
It worked! (class: LazyList)
42 changes: 0 additions & 42 deletions test/files/run/patmat-behavior.check
Expand Up @@ -88,30 +88,6 @@ patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A]
patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A] cannot also be a s.C11[A]
def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:36: warning: match may not be exhaustive.
It would fail on the following inputs: (x: Any forSome x not in (s.C00[?], s.C01[?], s.C10[?], s.C11[?], s.C20[?], s.C21[?])), ??, C01(_), C11(_, _), C21(_, _, _)
def ga1(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 }
^
patmat-behavior.scala:37: warning: match may not be exhaustive.
It would fail on the following inputs: (x: Any forSome x not in (s.C00[?], s.C01[?], s.C10[?], s.C11[?], s.C20[?], s.C21[?])), ??, C01(_), C11(_, _), C21(_, _, _)
def ga2(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 }
^
patmat-behavior.scala:38: warning: match may not be exhaustive.
It would fail on the following inputs: (x: Any forSome x not in (s.C00[?], s.C01[?], s.C10[?], s.C11[?], s.C20[?], s.C21[?])), ??, C01(_), C11(_, _), C21(_, _, _)
def ga3(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 }
^
patmat-behavior.scala:39: warning: match may not be exhaustive.
It would fail on the following inputs: (x: Any forSome x not in (s.C00[?], s.C01[?], s.C10[?], s.C11[?], s.C20[?], s.C21[?])), ??, C01(_), C11(_, _), C21(_, _, _)
def ga4(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 }
^
patmat-behavior.scala:40: warning: match may not be exhaustive.
It would fail on the following inputs: (x: Any forSome x not in (s.C00[?], s.C01[?], s.C10[?], s.C11[?], s.C20[?], s.C21[?])), ??, C01(_), C11(_, _), C21(_, _, _)
def ga5(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 }
^
patmat-behavior.scala:41: warning: match may not be exhaustive.
It would fail on the following inputs: (x: Any forSome x not in (s.C00[?], s.C01[?], s.C10[?], s.C11[?], s.C20[?], s.C21[?])), ??, C01(_), C11(_, _), C21(_, _, _)
def ga6(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 }
^
patmat-behavior.scala:43: warning: match may not be exhaustive.
It would fail on the following inputs: C00(), C01(_), C10(_), C11(_, _), C20(_, _), C21(_, _, _)
def gb1[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x }
Expand Down Expand Up @@ -160,24 +136,6 @@ patmat-behavior.scala:55: warning: match may not be exhaustive.
It would fail on the following inputs: C00(), C01(_), C10(_), C11(_, _), C20(_, _), C21(_, _, _)
def gc6[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:57: warning: match may not be exhaustive.
def gd1[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:58: warning: match may not be exhaustive.
def gd2[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:59: warning: match may not be exhaustive.
def gd3[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:60: warning: match may not be exhaustive.
def gd4[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:61: warning: match may not be exhaustive.
def gd5[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:62: warning: match may not be exhaustive.
def gd6[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x }
^
patmat-behavior.scala:68: warning: match may not be exhaustive.
It would fail on the following input: C00()
def gb1[A](x: C00[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x }
Expand Down