diff options
author | Lukas Rytz <lukas.rytz@typesafe.com> | 2016-01-14 08:42:31 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@typesafe.com> | 2016-01-14 08:42:31 +0100 |
commit | d16918db010b2805677254e748a617c417df98ec (patch) | |
tree | d32b87041284317fea2be49ec6578a35afb35671 | |
parent | 14d0931053f94963b1f734ad0a6cd22196b8474f (diff) | |
parent | 11783c3c2a6692cfbb41b14734504b86101ed955 (diff) | |
download | scala-d16918db010b2805677254e748a617c417df98ec.tar.gz scala-d16918db010b2805677254e748a617c417df98ec.tar.bz2 scala-d16918db010b2805677254e748a617c417df98ec.zip |
Merge pull request #4898 from soc/SI-8700
SI-8700 Exhaustiveness warning for enums from Java source
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 7 | ||||
-rw-r--r-- | test/files/neg/t8700a.check | 11 | ||||
-rw-r--r-- | test/files/neg/t8700a.flags | 1 | ||||
-rw-r--r-- | test/files/neg/t8700a/Bar.scala | 9 | ||||
-rw-r--r-- | test/files/neg/t8700a/Baz.java | 11 | ||||
-rw-r--r-- | test/files/neg/t8700a/Foo.java | 4 | ||||
-rw-r--r-- | test/files/neg/t8700b.check | 11 | ||||
-rw-r--r-- | test/files/neg/t8700b.flags | 1 | ||||
-rw-r--r-- | test/files/neg/t8700b/Bar_2.scala | 9 | ||||
-rw-r--r-- | test/files/neg/t8700b/Baz_1.java | 11 | ||||
-rw-r--r-- | test/files/neg/t8700b/Foo_1.java | 4 |
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 +} |