Skip to content

Commit 29e1f8a

Browse files
committed
Test final object is indeed redundant: objects must be JVM-final
Scalac sometimes *forgets* the final bytecode flag, and sometimes one cares, so people even *recommend* always writing *final object* instead of object. That's bad, since we started warning about it in #4973. scala/bug#11094 (comment) https://nrinaudo.github.io/scala-best-practices/adts/final_case_objects.html Why care? ========= If we forget the final flag in bytecode, Java code might then extend the class. Performance might or might not be affected - some in scala/contributors debated this for ~20 minutes (starting at https://gitter.im/scala/contributors?at=5c423c449bfa375aab21f2af).
1 parent 4ecbb60 commit 29e1f8a

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,4 +565,62 @@ class TestBCode extends DottyBytecodeTest {
565565
assertEquals(14, instructionsFromMethod(method).size)
566566
}
567567
}
568+
569+
/* Test that objects compile to *final* classes. */
570+
571+
def checkFinalClass(outputClassName: String, source: String) = {
572+
checkBCode(source) {
573+
dir =>
574+
val moduleIn = dir.lookupName(outputClassName, directory = false)
575+
val moduleNode = loadClassNode(moduleIn.input)
576+
assert((moduleNode.access & Opcodes.ACC_FINAL) != 0)
577+
}
578+
}
579+
580+
@Test def objectsAreFinal =
581+
checkFinalClass("Foo$.class", "object Foo")
582+
583+
@Test def objectsInClassAreFinal =
584+
checkFinalClass("Test$Foo$.class",
585+
"""class Test {
586+
| object Foo
587+
|}
588+
""".stripMargin)
589+
590+
@Test def objectsInObjsAreFinal =
591+
checkFinalClass("Test$Foo$.class",
592+
"""object Test {
593+
| object Foo
594+
|}
595+
""".stripMargin)
596+
597+
@Test def objectsInObjDefAreFinal =
598+
checkFinalClass("Test$Foo$1$.class",
599+
"""
600+
|object Test {
601+
| def bar() = {
602+
| object Foo
603+
| }
604+
|}
605+
""".stripMargin)
606+
607+
@Test def objectsInClassDefAreFinal =
608+
checkFinalClass("Test$Foo$1$.class",
609+
"""
610+
|class Test {
611+
| def bar() = {
612+
| object Foo
613+
| }
614+
|}
615+
""".stripMargin)
616+
617+
@Test def objectsInObjValAreFinal =
618+
checkFinalClass("Test$Foo$1$.class",
619+
"""
620+
|class Test {
621+
| val bar = {
622+
| object Foo
623+
| }
624+
|}
625+
""".stripMargin)
568626
}

0 commit comments

Comments
 (0)