Skip to content

Fix #5924: don't move static to interfaces #5932

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/LazyVals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/MoveStatics.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
}
9 changes: 9 additions & 0 deletions tests/run/i5924.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
trait Matchers {
object Helper
}

object Matchers extends Matchers

object Test {
def main(args: Array[String]): Unit = Matchers
}
13 changes: 13 additions & 0 deletions tests/run/i5924b.scala
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions tests/run/i5924c.scala
Original file line number Diff line number Diff line change
@@ -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
}