summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Ochsenreither <simon@ochsenreither.de>2016-01-07 19:07:45 +0100
committerSimon Ochsenreither <simon@ochsenreither.de>2016-01-14 00:01:40 +0100
commit11783c3c2a6692cfbb41b14734504b86101ed955 (patch)
tree094d7e5b3155f2325e8d6d290772433b1382228e
parentfb22e2b0a73605d654c153e02d454e5cec21f355 (diff)
downloadscala-11783c3c2a6692cfbb41b14734504b86101ed955.tar.gz
scala-11783c3c2a6692cfbb41b14734504b86101ed955.tar.bz2
scala-11783c3c2a6692cfbb41b14734504b86101ed955.zip
SI-8700 Exhaustiveness warning for enums from Java source
Until now, the warning was only emitted for enums from Java class files. This commit fixes it by - aligning the flags set in JavaParsers with the flags set in ClassfileParser (which are required by the pattern matcher to even consider checking exhaustiveness) - adding the enum members as childs to the class holding the enum as done in ClassfileParser so that the pattern matcher sees the enum members when looking for the sealed children of a type
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala2
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaParsers.scala12
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala7
-rw-r--r--test/files/neg/t8700a.check11
-rw-r--r--test/files/neg/t8700a.flags1
-rw-r--r--test/files/neg/t8700a/Bar.scala9
-rw-r--r--test/files/neg/t8700a/Baz.java11
-rw-r--r--test/files/neg/t8700a/Foo.java4
-rw-r--r--test/files/neg/t8700b.check11
-rw-r--r--test/files/neg/t8700b.flags1
-rw-r--r--test/files/neg/t8700b/Bar_2.scala9
-rw-r--r--test/files/neg/t8700b/Baz_1.java11
-rw-r--r--test/files/neg/t8700b/Foo_1.java4
14 files changed, 82 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 3696bb3daf..53304d137f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -671,7 +671,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
// Primitives are "abstract final" to prohibit instantiation
// without having to provide any implementations, but that is an
// illegal combination of modifiers at the bytecode level so
- // suppress final if abstract if present.
+ // suppress final if abstract is present.
import asm.Opcodes._
GenBCode.mkFlags(
if (privateFlag) ACC_PRIVATE else ACC_PUBLIC,
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
index eb25eb6e06..7224523a41 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
@@ -800,16 +800,10 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
val superclazz =
AppliedTypeTree(javaLangDot(tpnme.Enum), List(enumType))
val finalFlag = if (enumIsFinal) Flags.FINAL else 0l
- val abstractFlag = {
- // javac adds `ACC_ABSTRACT` to enum classes with deferred members
- val hasAbstractMember = body exists {
- case d: DefDef => d.mods.isDeferred
- case _ => false
- }
- if (hasAbstractMember) Flags.ABSTRACT else 0l
- }
addCompanionObject(consts ::: statics ::: predefs, atPos(pos) {
- ClassDef(mods | Flags.JAVA_ENUM | finalFlag | abstractFlag, name, List(),
+ // Marking the enum class SEALED | ABSTRACT enables exhaustiveness checking. See also ClassfileParser.
+ // This is a bit of a hack and requires excluding the ABSTRACT flag in the backend, see method javaClassfileFlags.
+ ClassDef(mods | Flags.JAVA_ENUM | Flags.SEALED | Flags.ABSTRACT | finalFlag, name, List(),
makeTemplate(superclazz :: interfaces, body))
})
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 99e61d2482..406411f21f 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -542,7 +542,7 @@ abstract class ClassfileParser {
devWarning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.")
case linked =>
if (!linked.isSealed)
- // Marking the enum class SEALED | ABSTRACT enables exhaustiveness checking.
+ // Marking the enum class SEALED | ABSTRACT enables exhaustiveness checking. See also JavaParsers.
// This is a bit of a hack and requires excluding the ABSTRACT flag in the backend, see method javaClassfileFlags.
linked setFlag (SEALED | ABSTRACT)
linked addChild sym
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index e01edd196e..0b6b6065f3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -653,8 +653,10 @@ trait Namers extends MethodSynthesis {
if (isScala && deriveAccessors(tree)) enterGetterSetter(tree)
else assignAndEnterFinishedSymbol(tree)
- if (isEnumConstant(tree))
+ if (isEnumConstant(tree)) {
tree.symbol setInfo ConstantType(Constant(tree.symbol))
+ tree.symbol.owner.linkedClassOfClass addChild tree.symbol
+ }
}
def enterLazyVal(tree: ValDef, lazyAccessor: Symbol): TermSymbol = {
@@ -1657,7 +1659,8 @@ trait Namers extends MethodSynthesis {
checkWithDeferred(FINAL)
}
- checkNoConflict(FINAL, SEALED)
+ if (!sym.isJavaEnum)
+ checkNoConflict(FINAL, SEALED)
checkNoConflict(PRIVATE, PROTECTED)
// checkNoConflict(PRIVATE, OVERRIDE) // this one leads to bad error messages like #4174, so catch in refchecks
// checkNoConflict(PRIVATE, FINAL) // can't do this because FINAL also means compile-time constant
diff --git a/test/files/neg/t8700a.check b/test/files/neg/t8700a.check
new file mode 100644
index 0000000000..ce7945a3fc
--- /dev/null
+++ b/test/files/neg/t8700a.check
@@ -0,0 +1,11 @@
+Bar.scala:2: warning: match may not be exhaustive.
+It would fail on the following input: B
+ def bar1(foo: Foo) = foo match {
+ ^
+Bar.scala:6: warning: match may not be exhaustive.
+It would fail on the following input: B
+ def bar2(foo: Baz) = foo match {
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+two warnings found
+one error found
diff --git a/test/files/neg/t8700a.flags b/test/files/neg/t8700a.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/t8700a.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/t8700a/Bar.scala b/test/files/neg/t8700a/Bar.scala
new file mode 100644
index 0000000000..33ad8e9877
--- /dev/null
+++ b/test/files/neg/t8700a/Bar.scala
@@ -0,0 +1,9 @@
+object Bar {
+ def bar1(foo: Foo) = foo match {
+ case Foo.A => 1
+ }
+
+ def bar2(foo: Baz) = foo match {
+ case Baz.A => 1
+ }
+}
diff --git a/test/files/neg/t8700a/Baz.java b/test/files/neg/t8700a/Baz.java
new file mode 100644
index 0000000000..f85ad40802
--- /dev/null
+++ b/test/files/neg/t8700a/Baz.java
@@ -0,0 +1,11 @@
+public enum Baz {
+ A {
+ public void baz1() {}
+ },
+ B {
+ public void baz1() {}
+ };
+
+ public abstract void baz1();
+ public void baz2() {}
+}
diff --git a/test/files/neg/t8700a/Foo.java b/test/files/neg/t8700a/Foo.java
new file mode 100644
index 0000000000..cc8e9daf1f
--- /dev/null
+++ b/test/files/neg/t8700a/Foo.java
@@ -0,0 +1,4 @@
+public enum Foo {
+ A,
+ B
+}
diff --git a/test/files/neg/t8700b.check b/test/files/neg/t8700b.check
new file mode 100644
index 0000000000..3bff78dd29
--- /dev/null
+++ b/test/files/neg/t8700b.check
@@ -0,0 +1,11 @@
+Bar_2.scala:2: warning: match may not be exhaustive.
+It would fail on the following input: B
+ def bar1(foo: Foo_1) = foo match {
+ ^
+Bar_2.scala:6: warning: match may not be exhaustive.
+It would fail on the following input: B
+ def bar2(foo: Baz_1) = foo match {
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+two warnings found
+one error found
diff --git a/test/files/neg/t8700b.flags b/test/files/neg/t8700b.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/t8700b.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/t8700b/Bar_2.scala b/test/files/neg/t8700b/Bar_2.scala
new file mode 100644
index 0000000000..97ba16df27
--- /dev/null
+++ b/test/files/neg/t8700b/Bar_2.scala
@@ -0,0 +1,9 @@
+object Bar {
+ def bar1(foo: Foo_1) = foo match {
+ case Foo_1.A => 1
+ }
+
+ def bar2(foo: Baz_1) = foo match {
+ case Baz_1.A => 1
+ }
+}
diff --git a/test/files/neg/t8700b/Baz_1.java b/test/files/neg/t8700b/Baz_1.java
new file mode 100644
index 0000000000..6a057c2c9c
--- /dev/null
+++ b/test/files/neg/t8700b/Baz_1.java
@@ -0,0 +1,11 @@
+public enum Baz_1 {
+ A {
+ public void baz1() {}
+ },
+ B {
+ public void baz1() {}
+ };
+
+ public abstract void baz1();
+ public void baz2() {}
+}
diff --git a/test/files/neg/t8700b/Foo_1.java b/test/files/neg/t8700b/Foo_1.java
new file mode 100644
index 0000000000..22656bdedd
--- /dev/null
+++ b/test/files/neg/t8700b/Foo_1.java
@@ -0,0 +1,4 @@
+public enum Foo_1 {
+ A,
+ B
+}