diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index dd04f7ddec2d..52952976094e 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -231,6 +231,9 @@ trait BCodeSkelBuilder extends BCodeHelpers { val javagensig = getGenericSignature(f, claszSymbol) val flags = javaFieldFlags(f) + assert(!f.isStaticMember || !claszSymbol.isInterface || !f.isMutable, + s"interface $claszSymbol cannot have non-final static field $f") + val jfield = new asm.tree.FieldNode( flags, f.javaSimpleName.toString, diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index b440804f9794..473197bc8eff 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -36,8 +36,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { override def changesMembers: Boolean = true // the phase adds lazy val accessors - def transformer: LazyVals = new LazyVals - val containerFlags: FlagSet = Synthetic | Mutable | Lazy val initFlags: FlagSet = Synthetic | Method diff --git a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala index 059ab19165cf..e9e9cf6aeed4 100644 --- a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala +++ b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala @@ -24,11 +24,11 @@ class MoveStatics extends MiniPhase with SymTransformer { override def phaseName: String = MoveStatics.name def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = { - if (sym.hasAnnotation(defn.ScalaStaticAnnot) && sym.owner.is(Flags.Module) && sym.owner.companionClass.exists) { + if (sym.hasAnnotation(defn.ScalaStaticAnnot) && sym.owner.is(Flags.Module) && sym.owner.companionClass.exists && + (sym.is(Flags.Method) || !(sym.is(Flags.Mutable) && sym.owner.companionClass.is(Flags.Trait)))) { sym.owner.asClass.delete(sym.symbol) sym.owner.companionClass.asClass.enter(sym.symbol) - val flags = if (sym.is(Flags.Method)) sym.flags else sym.flags | Flags.Mutable - sym.copySymDenotation(owner = sym.owner.companionClass, initFlags = flags) + sym.copySymDenotation(owner = sym.owner.companionClass) } else sym } @@ -58,11 +58,11 @@ class MoveStatics extends MiniPhase with SymTransformer { } def move(module: TypeDef, companion: TypeDef): List[Tree] = { - assert(companion ne module) + assert(companion != module) if (!module.symbol.is(Flags.Module)) move(companion, module) else { val allMembers = - (if(companion ne null) {companion.rhs.asInstanceOf[Template].body} else Nil) ++ + (if(companion != null) {companion.rhs.asInstanceOf[Template].body} else Nil) ++ module.rhs.asInstanceOf[Template].body val (newModuleBody, newCompanionBody) = allMembers.partition(x => {assert(x.symbol.exists); x.symbol.owner == module.symbol}) Trees.flatten(rebuild(companion, newCompanionBody) :: rebuild(module, newModuleBody) :: Nil) diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala index 1c8648455c7e..842164339b24 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala @@ -73,6 +73,10 @@ trait DottyBytecodeTest { classNode.methods.asScala.find(_.name == name) getOrElse sys.error(s"Didn't find method '$name' in class '${classNode.name}'") + protected def getField(classNode: ClassNode, name: String): FieldNode = + classNode.fields.asScala.find(_.name == name) getOrElse + sys.error(s"Didn't find field '$name' in class '${classNode.name}'") + def diffInstructions(isa: List[Instruction], isb: List[Instruction]): String = { val len = Math.max(isa.length, isb.length) val sb = new StringBuilder diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index 75c90fe36a0d..ecb876bfae2a 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -695,4 +695,63 @@ class TestBCode extends DottyBytecodeTest { "`test` was not properly generated\n" + diffInstructions(instructions, expected)) } } + + @Test def i5924b = { + val source = + """|import scala.annotation.static + |trait Base + | + |object Base { + | @static val x = 10 + | @static final val y = 10 + | @static def f: Int = 30 + |} + """.stripMargin + + checkBCode(source) { dir => + val clsIn = dir.lookupName("Base.class", directory = false).input + val clsNode = loadClassNode(clsIn) + val f = getMethod(clsNode, "f") + val x = getField(clsNode, "x") + val y = getField(clsNode, "y") + assert((f.access & Opcodes.ACC_STATIC) != 0) + List(x, y).foreach { node => + assert((node.access & Opcodes.ACC_STATIC) != 0) + assert((node.access & Opcodes.ACC_FINAL) != 0) + } + } + } + + @Test def i5924c = { + val source = + """|import scala.annotation.static + |class Base + | + |object Base { + | @static val x = 10 + | @static final val y = 10 + | @static var a = 10 + | @static final var b = 10 + | @static def f: Int = 30 + |} + """.stripMargin + + checkBCode(source) { dir => + val clsIn = dir.lookupName("Base.class", directory = false).input + val clsNode = loadClassNode(clsIn) + val f = getMethod(clsNode, "f") + val x = getField(clsNode, "x") + val y = getField(clsNode, "y") + val a = getField(clsNode, "a") + val b = getField(clsNode, "b") + assert((f.access & Opcodes.ACC_STATIC) != 0) + List(x, y).foreach { node => + assert((node.access & Opcodes.ACC_STATIC) != 0) + assert((node.access & Opcodes.ACC_FINAL) != 0) + } + List(a, b).foreach { node => + assert((node.access & Opcodes.ACC_STATIC) != 0) + } + } + } } diff --git a/tests/run/i5924.scala b/tests/run/i5924.scala new file mode 100644 index 000000000000..595ed5f41070 --- /dev/null +++ b/tests/run/i5924.scala @@ -0,0 +1,9 @@ +trait Matchers { + object Helper +} + +object Matchers extends Matchers + +object Test { + def main(args: Array[String]): Unit = Matchers +} diff --git a/tests/run/i5924b.scala b/tests/run/i5924b.scala new file mode 100644 index 000000000000..9d76a53a1da5 --- /dev/null +++ b/tests/run/i5924b.scala @@ -0,0 +1,13 @@ +import scala.annotation.static + +trait Base + +object Base { + @static val x = 10 + @static final val y = 10 + @static def f: Int = 30 +} + +object Test { + def main(args: Array[String]): Unit = Base +} \ No newline at end of file diff --git a/tests/run/i5924c.scala b/tests/run/i5924c.scala new file mode 100644 index 000000000000..c86076d7e4e8 --- /dev/null +++ b/tests/run/i5924c.scala @@ -0,0 +1,15 @@ +import scala.annotation.static + +class Base + +object Base { + @static val x = 10 + @static final val y = 10 + @static var a = 10 + @static final var b = 10 + @static def f: Int = 30 +} + +object Test { + def main(args: Array[String]): Unit = Base +} \ No newline at end of file