aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2017-04-10 10:33:32 +0200
committerGitHub <noreply@github.com>2017-04-10 10:33:32 +0200
commit318700fdaacd7e6707519e03f15a5ede99ca558a (patch)
tree809f66b68f9200afd8daef9172921405469a39c7
parent80f9b6da66cb4eeabfd5ab97e422752ff134d590 (diff)
parent2bf1e1913feb36d90d1c4e857c6cd9610d80ff61 (diff)
downloaddotty-318700fdaacd7e6707519e03f15a5ede99ca558a.tar.gz
dotty-318700fdaacd7e6707519e03f15a5ede99ca558a.tar.bz2
dotty-318700fdaacd7e6707519e03f15a5ede99ca558a.zip
Merge pull request #2197 from dotty-staging/add-enum-exhaustiveness
Add enum exhaustivity checking
-rw-r--r--compiler/src/dotty/tools/dotc/config/Printers.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/PostTyper.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/transform/patmat/Space.scala161
-rw-r--r--tests/patmat/enum-HList.scala22
-rw-r--r--tests/patmat/enum-Tree.scala29
-rw-r--r--tests/patmat/enumColor.scala12
-rw-r--r--tests/patmat/patmat-indent.check2
-rw-r--r--tests/patmat/patmat-indent.scala2
-rw-r--r--tests/patmat/planets.scala26
-rw-r--r--tests/patmat/t6420.check2
-rw-r--r--tests/patmat/t7285.check2
-rw-r--r--tests/patmat/t7466.check2
-rw-r--r--tests/run/enum-Color.scala4
14 files changed, 175 insertions, 105 deletions
diff --git a/compiler/src/dotty/tools/dotc/config/Printers.scala b/compiler/src/dotty/tools/dotc/config/Printers.scala
index 002d0f933..a77607d18 100644
--- a/compiler/src/dotty/tools/dotc/config/Printers.scala
+++ b/compiler/src/dotty/tools/dotc/config/Printers.scala
@@ -31,4 +31,5 @@ object Printers {
val cyclicErrors: Printer = noPrinter
val pickling: Printer = noPrinter
val inlining: Printer = noPrinter
+ val exhaustivity: Printer = noPrinter
}
diff --git a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala
index ebd2ae436..b48d219d6 100644
--- a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala
+++ b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala
@@ -147,6 +147,9 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
(scTrait && selTrait)
val inMatch = s.qualifier.symbol is Case
+ // FIXME: This will misclassify case objects! We need to find another way to characterize
+ // isInstanceOfs generated by matches.
+ // Probably the most robust way is to use another symbol for the isInstanceOf method.
if (valueClassesOrAny) tree
else if (knownStatically)
diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
index 9821757e8..bacb88091 100644
--- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -104,8 +104,14 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
private def transformAnnot(annot: Annotation)(implicit ctx: Context): Annotation =
annot.derivedAnnotation(transformAnnot(annot.tree))
+ private def registerChild(sym: Symbol, tp: Type)(implicit ctx: Context) = {
+ val cls = tp.classSymbol
+ if (cls.is(Sealed)) cls.addAnnotation(Annotation.makeChild(sym))
+ }
+
private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
val sym = tree.symbol
+ if (sym.is(CaseVal, butNot = Method | Module)) registerChild(sym, sym.info)
sym.transformAnnotations(transformAnnot)
}
@@ -227,9 +233,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
// Add Child annotation to sealed parents unless current class is anonymous
if (!sym.isAnonymousClass) // ignore anonymous class
- for (parent <- sym.asClass.classInfo.classParents) {
- val pclazz = parent.classSymbol
- if (pclazz.is(Sealed)) pclazz.addAnnotation(Annotation.makeChild(sym))
+ sym.asClass.classInfo.classParents.foreach { parent =>
+ val sym2 = if (sym.is(Module)) sym.sourceModule else sym
+ registerChild(sym2, parent)
}
tree
diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
index 8d926fcf0..baf1ae356 100644
--- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
+++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
@@ -13,6 +13,7 @@ import core.StdNames._
import core.NameOps._
import core.Constants._
import reporting.diagnostic.messages._
+import config.Printers.{ exhaustivity => debug }
/** Space logic for checking exhaustivity and unreachability of pattern matching
*
@@ -28,8 +29,6 @@ import reporting.diagnostic.messages._
* 3. A union of spaces `S1 | S2 | ...` is a space
* 4. For a case class Kon(x1: T1, x2: T2, .., xn: Tn), if S1, S2, ..., Sn
* are spaces, then `Kon(S1, S2, ..., Sn)` is a space.
- * 5. A constant `Const(value, T)` is a point in space
- * 6. A stable identifier `Var(sym, T)` is a space
*
* For the problem of exhaustivity check, its formulation in terms of space is as follows:
*
@@ -67,15 +66,6 @@ case class Kon(tp: Type, params: List[Space]) extends Space
/** Union of spaces */
case class Or(spaces: List[Space]) extends Space
-/** Point in space */
-sealed trait Point extends Space
-
-/** Point representing variables(stable identifier) in patterns */
-case class Var(sym: Symbol, tp: Type) extends Point
-
-/** Point representing literal constants in patterns */
-case class Const(value: Constant, tp: Type) extends Point
-
/** abstract space logic */
trait SpaceLogic {
/** Is `tp1` a subtype of `tp2`? */
@@ -97,6 +87,9 @@ trait SpaceLogic {
/** Get components of decomposable types */
def decompose(tp: Type): List[Space]
+ /** Display space in string format */
+ def show(sp: Space): String
+
/** Simplify space using the laws, there's no nested union after simplify */
def simplify(space: Space): Space = space match {
case Kon(tp, spaces) =>
@@ -137,7 +130,7 @@ trait SpaceLogic {
def tryDecompose1(tp: Type) = canDecompose(tp) && isSubspace(Or(decompose(tp)), b)
def tryDecompose2(tp: Type) = canDecompose(tp) && isSubspace(a, Or(decompose(tp)))
- (a, b) match {
+ val res = (a, b) match {
case (Empty, _) => true
case (_, Empty) => false
case (Or(ss), _) => ss.forall(isSubspace(_, b))
@@ -157,17 +150,11 @@ trait SpaceLogic {
simplify(minus(a, b)) == Empty
case (Kon(tp1, ss1), Kon(tp2, ss2)) =>
isEqualType(tp1, tp2) && ss1.zip(ss2).forall((isSubspace _).tupled)
- case (Const(v1, _), Const(v2, _)) => v1 == v2
- case (Const(_, tp1), Typ(tp2, _)) => isSubType(tp1, tp2) || tryDecompose2(tp2)
- case (Const(_, _), Or(ss)) => ss.exists(isSubspace(a, _))
- case (Const(_, _), _) => false
- case (_, Const(_, _)) => false
- case (Var(x, _), Var(y, _)) => x == y
- case (Var(_, tp1), Typ(tp2, _)) => isSubType(tp1, tp2) || tryDecompose2(tp2)
- case (Var(_, _), Or(ss)) => ss.exists(isSubspace(a, _))
- case (Var(_, _), _) => false
- case (_, Var(_, _)) => false
}
+
+ debug.println(s"${show(a)} < ${show(b)} = $res")
+
+ res
}
/** Intersection of two spaces */
@@ -175,7 +162,7 @@ trait SpaceLogic {
def tryDecompose1(tp: Type) = intersect(Or(decompose(tp)), b)
def tryDecompose2(tp: Type) = intersect(a, Or(decompose(tp)))
- (a, b) match {
+ val res = (a, b) match {
case (Empty, _) | (_, Empty) => Empty
case (_, Or(ss)) => Or(ss.map(intersect(a, _)).filterConserve(_ ne Empty))
case (Or(ss), _) => Or(ss.map(intersect(_, b)).filterConserve(_ ne Empty))
@@ -199,31 +186,11 @@ trait SpaceLogic {
if (!isEqualType(tp1, tp2)) Empty
else if (ss1.zip(ss2).exists(p => simplify(intersect(p._1, p._2)) == Empty)) Empty
else Kon(tp1, ss1.zip(ss2).map((intersect _).tupled))
- case (Const(v1, _), Const(v2, _)) =>
- if (v1 == v2) a else Empty
- case (Const(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) a
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else Empty
- case (Const(_, _), _) => Empty
- case (Typ(tp1, _), Const(_, tp2)) =>
- if (isSubType(tp2, tp1)) b
- else if (canDecompose(tp1)) tryDecompose1(tp1)
- else Empty
- case (_, Const(_, _)) => Empty
- case (Var(x, _), Var(y, _)) =>
- if (x == y) a else Empty
- case (Var(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) a
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else Empty
- case (Var(_, _), _) => Empty
- case (Typ(tp1, _), Var(_, tp2)) =>
- if (isSubType(tp2, tp1)) b
- else if (canDecompose(tp1)) tryDecompose1(tp1)
- else Empty
- case (_, Var(_, _)) => Empty
}
+
+ debug.println(s"${show(a)} & ${show(b)} = ${show(res)}")
+
+ res
}
/** The space of a not covered by b */
@@ -231,7 +198,7 @@ trait SpaceLogic {
def tryDecompose1(tp: Type) = minus(Or(decompose(tp)), b)
def tryDecompose2(tp: Type) = minus(a, Or(decompose(tp)))
- (a, b) match {
+ val res = (a, b) match {
case (Empty, _) => Empty
case (_, Empty) => a
case (Typ(tp1, _), Typ(tp2, _)) =>
@@ -264,26 +231,11 @@ trait SpaceLogic {
Or(ss1.zip(ss2).map((minus _).tupled).zip(0 to ss2.length - 1).map {
case (ri, i) => Kon(tp1, ss1.updated(i, ri))
})
- case (Const(v1, _), Const(v2, _)) =>
- if (v1 == v2) Empty else a
- case (Const(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) Empty
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else a
- case (Const(_, _), _) => a
- case (Typ(tp1, _), Const(_, tp2)) => // Boolean & Java enum
- if (canDecompose(tp1)) tryDecompose1(tp1)
- else a
- case (_, Const(_, _)) => a
- case (Var(x, _), Var(y, _)) =>
- if (x == y) Empty else a
- case (Var(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) Empty
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else a
- case (Var(_, _), _) => a
- case (_, Var(_, _)) => a
}
+
+ debug.println(s"${show(a)} - ${show(b)} = ${show(res)}")
+
+ res
}
}
@@ -297,19 +249,14 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
* otherwise approximate extractors to Empty
*/
def project(pat: Tree, roundUp: Boolean = true)(implicit ctx: Context): Space = pat match {
- case Literal(c) => Const(c, c.tpe)
- case _: BackquotedIdent => Var(pat.symbol, pat.tpe)
+ case Literal(c) =>
+ if (c.value.isInstanceOf[Symbol])
+ Typ(c.value.asInstanceOf[Symbol].termRef, false)
+ else
+ Typ(ConstantType(c), false)
+ case _: BackquotedIdent => Typ(pat.tpe, false)
case Ident(_) | Select(_, _) =>
- pat.tpe.stripAnnots match {
- case tp: TermRef =>
- if (pat.symbol.is(Enum))
- Const(Constant(pat.symbol), tp)
- else if (tp.underlyingIterator.exists(_.classSymbol.is(Module)))
- Typ(tp.widenTermRefExpr.stripAnnots, false)
- else
- Var(pat.symbol, tp)
- case tp => Typ(tp, false)
- }
+ Typ(pat.tpe.stripAnnots, false)
case Alternative(trees) => Or(trees.map(project(_, roundUp)))
case Bind(_, pat) => project(pat)
case UnApply(_, _, pats) =>
@@ -345,7 +292,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
/** Is `tp1` a subtype of `tp2`? */
def isSubType(tp1: Type, tp2: Type): Boolean = {
// check SI-9657 and tests/patmat/gadt.scala
- erase(tp1) <:< erase(tp2)
+ val res = erase(tp1) <:< erase(tp2)
+ debug.println(s"${tp1.show} <:< ${tp2.show} = $res")
+ res
}
def isEqualType(tp1: Type, tp2: Type): Boolean = tp1 =:= tp2
@@ -373,19 +322,23 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
}
}
+ debug.println(s"candidates for ${tp.show} : [${children.map(_.show).mkString(", ")}]")
+
tp match {
case OrType(tp1, tp2) => List(Typ(tp1, true), Typ(tp2, true))
case _ if tp =:= ctx.definitions.BooleanType =>
List(
- Const(Constant(true), ctx.definitions.BooleanType),
- Const(Constant(false), ctx.definitions.BooleanType)
+ Typ(ConstantType(Constant(true)), true),
+ Typ(ConstantType(Constant(false)), true)
)
case _ if tp.classSymbol.is(Enum) =>
- children.map(sym => Const(Constant(sym), tp))
+ children.map(sym => Typ(sym.termRef, true))
case _ =>
val parts = children.map { sym =>
if (sym.is(ModuleClass))
- sym.asClass.classInfo.selfType
+ refine(tp, sym.sourceModule.termRef)
+ else if (sym.isTerm)
+ refine(tp, sym.termRef)
else if (sym.info.typeParams.length > 0 || tp.isInstanceOf[TypeRef])
refine(tp, sym.typeRef)
else
@@ -393,9 +346,13 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
} filter { tpe =>
// Child class may not always be subtype of parent:
// GADT & path-dependent types
- tpe <:< expose(tp)
+ val res = tpe <:< expose(tp)
+ if (!res) debug.println(s"unqualified child ousted: ${tpe.show} !< ${tp.show}")
+ res
}
+ debug.println(s"${tp.show} decomposes to [${parts.map(_.show).mkString(", ")}]")
+
parts.map(Typ(_, true))
}
}
@@ -409,20 +366,26 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
* `path2`, then return `path1.B`.
*/
def refine(tp1: Type, tp2: Type): Type = (tp1, tp2) match {
- case (tp1: RefinedType, _) => tp1.wrapIfMember(refine(tp1.parent, tp2))
+ case (tp1: RefinedType, _: TypeRef) => tp1.wrapIfMember(refine(tp1.parent, tp2))
case (tp1: HKApply, _) => refine(tp1.superType, tp2)
- case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, name)) =>
- if (ref1.underlying <:< ref2.underlying) TypeRef(ref1, name) else tp2
+ case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) =>
+ if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2
+ case (TypeRef(ref1: TypeProxy, _), tp2 @ TermRef(ref2: TypeProxy, _)) =>
+ if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2
case _ => tp2
}
/** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */
def canDecompose(tp: Type): Boolean = {
- tp.classSymbol.is(allOf(Abstract, Sealed)) ||
+ val res = tp.classSymbol.is(allOf(Abstract, Sealed)) ||
tp.classSymbol.is(allOf(Trait, Sealed)) ||
tp.isInstanceOf[OrType] ||
tp =:= ctx.definitions.BooleanType ||
- tp.classSymbol.is(Enum)
+ tp.classSymbol.is(allOf(Enum, Sealed)) // Enum value doesn't have Sealed flag
+
+ debug.println(s"decomposable: ${tp.show} = $res")
+
+ res
}
/** Show friendly type name with current scope in mind
@@ -474,14 +437,12 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
def show(s: Space): String = {
def doShow(s: Space, mergeList: Boolean = false): String = s match {
case Empty => ""
- case Const(v, _) => v.show
- case Var(x, _) => x.show
+ case Typ(c: ConstantType, _) => c.value.show
+ case Typ(tp: TermRef, _) => tp.symbol.showName
case Typ(tp, decomposed) =>
val sym = tp.widen.classSymbol
- if (sym.is(ModuleClass))
- showType(tp)
- else if (ctx.definitions.isTupleType(tp))
+ if (ctx.definitions.isTupleType(tp))
signature(tp).map(_ => "_").mkString("(", ", ", ")")
else if (sym.showFullName == "scala.collection.immutable.::")
if (mergeList) "_" else "List(_)"
@@ -523,7 +484,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
}
val Match(sel, cases) = tree
- isCheckable(sel.tpe.widen.deAnonymize.dealiasKeepAnnots)
+ val res = isCheckable(sel.tpe.widen.deAnonymize.dealiasKeepAnnots)
+ debug.println(s"checkable: ${sel.show} = $res")
+ res
}
@@ -584,7 +547,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
val selTyp = sel.tpe.widen.deAnonymize.dealias
- val patternSpace = cases.map(x => project(x.pat)).reduce((a, b) => Or(List(a, b)))
+ val patternSpace = cases.map({ x =>
+ val space = project(x.pat)
+ debug.println(s"${x.pat.show} projects to ${show(space)}")
+ space
+ }).reduce((a, b) => Or(List(a, b)))
val uncovered = simplify(minus(Typ(selTyp, true), patternSpace))
if (uncovered != Empty)
diff --git a/tests/patmat/enum-HList.scala b/tests/patmat/enum-HList.scala
new file mode 100644
index 000000000..c019cb6cc
--- /dev/null
+++ b/tests/patmat/enum-HList.scala
@@ -0,0 +1,22 @@
+enum HLst {
+ case HCons[+Hd, +Tl <: HLst](hd: Hd, tl: Tl)
+ case HNil
+}
+
+object Test {
+ import HLst._
+ def length(hl: HLst): Int = hl match {
+ case HCons(_, tl) => 1 + length(tl)
+ case HNil => 0
+ }
+ def sumInts(hl: HLst): Int = hl match {
+ case HCons(x: Int, tl) => x + sumInts(tl)
+ case HCons(_, tl) => sumInts(tl)
+ case HNil => 0
+ }
+ def main(args: Array[String]) = {
+ val hl = HCons(1, HCons("A", HNil))
+ assert(length(hl) == 2, length(hl))
+ assert(sumInts(hl) == 1)
+ }
+}
diff --git a/tests/patmat/enum-Tree.scala b/tests/patmat/enum-Tree.scala
new file mode 100644
index 000000000..ef5bd7a57
--- /dev/null
+++ b/tests/patmat/enum-Tree.scala
@@ -0,0 +1,29 @@
+enum Tree[T] {
+ case True extends Tree[Boolean]
+ case False extends Tree[Boolean]
+ case Zero extends Tree[Int]
+ case Succ(n: Tree[Int]) extends Tree[Int]
+ case Pred(n: Tree[Int]) extends Tree[Int]
+ case IsZero(n: Tree[Int]) extends Tree[Boolean]
+ case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
+}
+
+object Test {
+ import Tree._
+
+ def eval[T](e: Tree[T]): T = e match {
+ case True => true
+ case False => false
+ case Zero => 0
+ case Succ(f) => eval(f) + 1
+ case Pred(f) => eval(f) - 1
+ case IsZero(f) => eval(f) == 0
+ case If(cond, thenp, elsep) => if (eval(cond)) eval(thenp) else eval(elsep)
+ }
+
+ val data = If(IsZero(Pred(Succ(Zero))), Succ(Succ(Zero)), Pred(Pred(Zero)))
+
+ def main(args: Array[String]) = {
+ println(s"$data --> ${eval(data)}")
+ }
+}
diff --git a/tests/patmat/enumColor.scala b/tests/patmat/enumColor.scala
new file mode 100644
index 000000000..60d610d0d
--- /dev/null
+++ b/tests/patmat/enumColor.scala
@@ -0,0 +1,12 @@
+ enum Color {
+ case Red, Green, Blue
+ }
+
+ object Test {
+ def f(color: Color) = {
+ import Color._
+ color match {
+ case Red | Green | Blue =>
+ }
+ }
+}
diff --git a/tests/patmat/patmat-indent.check b/tests/patmat/patmat-indent.check
index 79845ebcf..4f0ec4dd9 100644
--- a/tests/patmat/patmat-indent.check
+++ b/tests/patmat/patmat-indent.check
@@ -1,3 +1,3 @@
9: Pattern Match Exhaustivity: Nil
-23: Pattern Match Exhaustivity: _: Boolean
+23: Pattern Match Exhaustivity: true, false
27: Pattern Match Exhaustivity: _: Int
diff --git a/tests/patmat/patmat-indent.scala b/tests/patmat/patmat-indent.scala
index ef25bb2c7..a2b18e7fb 100644
--- a/tests/patmat/patmat-indent.scala
+++ b/tests/patmat/patmat-indent.scala
@@ -1,5 +1,5 @@
object Test {
- val Nil = scala.Nil
+ val Nil: scala.collection.immutable.Nil.type = scala.collection.immutable.Nil
val X = 5
object Inner {
diff --git a/tests/patmat/planets.scala b/tests/patmat/planets.scala
new file mode 100644
index 000000000..bcbfd7eeb
--- /dev/null
+++ b/tests/patmat/planets.scala
@@ -0,0 +1,26 @@
+enum class Planet(mass: Double, radius: Double) {
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+}
+object Planet {
+ case MERCURY extends Planet(3.303e+23, 2.4397e6)
+ case VENUS extends Planet(4.869e+24, 6.0518e6)
+ case EARTH extends Planet(5.976e+24, 6.37814e6)
+ case MARS extends Planet(6.421e+23, 3.3972e6)
+ case JUPITER extends Planet(1.9e+27, 7.1492e7)
+ case SATURN extends Planet(5.688e+26, 6.0268e7)
+ case URANUS extends Planet(8.686e+25, 2.5559e7)
+ case NEPTUNE extends Planet(1.024e+26, 2.4746e7)
+}
+object Test {
+ def main(args: Array[String]) = {
+ import Planet._
+ assert(enumValueNamed("SATURN") == SATURN)
+ assert(enumValue(2) == EARTH)
+ val earthWeight = 100
+ val mass = earthWeight/EARTH.surfaceGravity
+ for (p <- enumValues)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+ }
+}
diff --git a/tests/patmat/t6420.check b/tests/patmat/t6420.check
index 73acf1454..c15701594 100644
--- a/tests/patmat/t6420.check
+++ b/tests/patmat/t6420.check
@@ -1 +1 @@
-5: Pattern Match Exhaustivity: (Nil, _), (List(_, _), _), (Nil, Nil), (Nil, List(_, _)), (List(_, _), Nil), (List(_, _), List(_, _)), (_, Nil), (_, List(_, _))
+5: Pattern Match Exhaustivity: (Nil, _), (List(true, _), _), (List(false, _), _), (_, Nil), (_, List(true, _)), (_, List(false, _))
diff --git a/tests/patmat/t7285.check b/tests/patmat/t7285.check
index 1c2841920..d40b77e4b 100644
--- a/tests/patmat/t7285.check
+++ b/tests/patmat/t7285.check
@@ -1,3 +1,3 @@
15: Pattern Match Exhaustivity: (Up, Down)
33: Pattern Match Exhaustivity: Down
-51: Pattern Match Exhaustivity: (Base.Up, Base.Down)
+51: Pattern Match Exhaustivity: (Up, Down)
diff --git a/tests/patmat/t7466.check b/tests/patmat/t7466.check
index 35227484e..af596399b 100644
--- a/tests/patmat/t7466.check
+++ b/tests/patmat/t7466.check
@@ -1 +1 @@
-8: Pattern Match Exhaustivity: (_, _)
+8: Pattern Match Exhaustivity: (true, _), (false, _), (_, true), (_, false)
diff --git a/tests/run/enum-Color.scala b/tests/run/enum-Color.scala
index 683d18d9e..f4f6aaef8 100644
--- a/tests/run/enum-Color.scala
+++ b/tests/run/enum-Color.scala
@@ -7,5 +7,9 @@ object Test {
for (color <- Color.enumValues) {
println(s"$color: ${color.enumTag}")
assert(Color.enumValue(color.enumTag) eq color)
+ import Color._
+ color match {
+ case Red | Green | Blue =>
+ }
}
}