diff --git a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala index 8044bb7496e8..74d37cdc54a8 100644 --- a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala +++ b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala @@ -200,16 +200,21 @@ class BTypesFromSymbols[I <: BackendInterface](val int: I) extends BTypes { val finalFlag = sym.getsJavaFinalFlag - // 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. import asm.Opcodes._ GenBCodeOps.mkFlags( if (privateFlag) ACC_PRIVATE else ACC_PUBLIC, if (sym.isDeferred || sym.hasAbstractFlag) ACC_ABSTRACT else 0, if (sym.isInterface) ACC_INTERFACE else 0, - if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0, + + if (finalFlag && + // 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. + !sym.hasAbstractFlag && + // Mixin forwarders are bridges and can be final, but final bridges confuse some frameworks + !sym.isBridge) + ACC_FINAL else 0, if (sym.isStaticMember) ACC_STATIC else 0, if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, if (sym.isArtifact) ACC_SYNTHETIC else 0, diff --git a/tests/run/t11485.scala b/tests/run/t11485.scala new file mode 100644 index 000000000000..e27b46119dda --- /dev/null +++ b/tests/run/t11485.scala @@ -0,0 +1,16 @@ +import java.lang.reflect.Modifier + +trait HaveFinalMethod { + final def finalMethod: String = "final" +} + +class Child extends HaveFinalMethod + +object Test { + def main(args: Array[String]): Unit = { + val meth = classOf[Child].getMethod("finalMethod") + assert(meth.isBridge) + val mods = meth.getModifiers + assert(!Modifier.isFinal(mods)) + } +}