diff --git a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala index bf275dfa7a62..54dafe6f0032 100644 --- a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala +++ b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala @@ -310,7 +310,7 @@ class BTypesFromSymbols[I <: DottyBackendInterface](val int: I) extends BTypes { // tests/run/serialize.scala and https://github.com/typelevel/cats-effect/pull/2360). val privateFlag = !sym.isClass && (sym.is(Private) || (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass)) - val finalFlag = sym.is(Final) && !toDenot(sym).isClassConstructor && !sym.is(Mutable) && !sym.enclosingClass.is(Trait) + val finalFlag = sym.is(Final) && !toDenot(sym).isClassConstructor && !sym.is(Mutable, butNot = Accessor) && !sym.enclosingClass.is(Trait) import asm.Opcodes._ import GenBCodeOps.addFlagIf diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index d21cf929b840..a4d04637f0a6 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -1557,6 +1557,29 @@ class DottyBytecodeTests extends DottyBytecodeTest { } } + /** Check that final mutable var accessors are final */ + @Test def i10835 = { + val source = + s"""class A { + | final var x = 1 + |} + |""".stripMargin + checkBCode(source){dir => + val clsIn = dir.lookupName("A.class", directory = false).input + val clsNode = loadClassNode(clsIn) + def isFinal(access: Int) = (access & Opcodes.ACC_FINAL) != 0 + + val field = clsNode.fields.asScala.find(_.name == "x").map(_.access) + assertTrue("field is not final", field.exists(!isFinal(_))) + assertTrue("field is private", field.exists(acc => (acc & Opcodes.ACC_PRIVATE) != 0)) + + val methods = clsNode.methods.asScala + def methodAccess(name: String) = methods.find(_.name == name).map(_.access) + assertTrue("getter is final", methodAccess("x").exists(isFinal)) + assertTrue("setter is final", methodAccess("x_$eq").exists(isFinal)) + } + } + /** Check that erasure if `Int | Nothing` is `int` */ @Test def i14970 = { val source =