Skip to content

Commit

Permalink
Merge pull request scala#11126 from dotty-staging/fix-8022
Browse files Browse the repository at this point in the history
Fix scala#8022: Refactor MoveStatics
  • Loading branch information
odersky committed Jan 19, 2021
2 parents b4d0cd4 + cdebeb6 commit d98b760
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 59 deletions.
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1943,7 +1943,7 @@ import transform.SymUtils._
}

class StaticFieldsOnlyAllowedInObjects(member: Symbol)(using Context) extends SyntaxMsg(StaticFieldsOnlyAllowedInObjectsID) {
def msg = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}."
def msg = em"${hl("@static")} $member in ${member.owner} must be defined inside a static ${hl("object")}."
def explain =
em"${hl("@static")} members are only allowed inside objects."
}
Expand Down
19 changes: 1 addition & 18 deletions compiler/src/dotty/tools/dotc/transform/CheckStatic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CheckStatic extends MiniPhase {
var hadNonStaticField = false
for (defn <- defns)
if (defn.symbol.isScalaStatic) {
if (!ctx.owner.is(Module))
if (!ctx.owner.isStaticOwner)
report.error(StaticFieldsOnlyAllowedInObjects(defn.symbol), defn.srcPos)
defn.symbol.resetFlag(JavaStatic)

Expand All @@ -59,23 +59,6 @@ class CheckStatic extends MiniPhase {

tree
}

override def transformSelect(tree: tpd.Select)(using Context): tpd.Tree =
if (tree.symbol.hasAnnotation(defn.ScalaStaticAnnot)) {
val symbolWhitelist = tree.symbol.ownersIterator.flatMap(x => if (x.is(Flags.Module)) List(x, x.companionModule) else List(x)).toSet
def isSafeQual(t: Tree): Boolean = // follow the desugared paths created by typer
t match {
case t: This => true
case t: Select => isSafeQual(t.qualifier) && symbolWhitelist.contains(t.symbol)
case t: Ident => symbolWhitelist.contains(t.symbol)
case t: Block => t.stats.forall(tpd.isPureExpr) && isSafeQual(t.expr)
case _ => false
}
if (isSafeQual(tree.qualifier))
ref(tree.symbol)
else tree
}
else tree
}

object CheckStatic {
Expand Down
64 changes: 37 additions & 27 deletions compiler/src/dotty/tools/dotc/transform/MoveStatics.scala
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
package dotty.tools.dotc.transform
package dotty.tools.dotc
package transform

import dotty.tools.dotc.ast.{Trees, tpd}
import dotty.tools.dotc.core.Annotations.Annotation
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.DenotTransformers.SymTransformer
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import dotty.tools.dotc.core.NameOps._
import dotty.tools.dotc.core.Flags
import dotty.tools.dotc.core.Names.Name
import dotty.tools.dotc.core.StdNames.nme
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.Types.MethodType
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
import core._
import Flags._
import Contexts._
import Symbols._
import Decorators._
import DenotTransformers.SymTransformer
import Types.MethodType
import Annotations.Annotation
import SymDenotations.SymDenotation
import Names.Name
import StdNames.nme
import NameOps._

object MoveStatics {
val name: String = "moveStatic"
}
import reporting._
import ast._

import SymUtils._
import MegaPhase._

/** Move static methods from companion to the class itself */
class MoveStatics extends MiniPhase with SymTransformer {
import ast.tpd._

import tpd._
override def phaseName: String = MoveStatics.name

def transformSym(sym: SymDenotation)(using Context): SymDenotation =
Expand All @@ -38,8 +41,6 @@ class MoveStatics extends MiniPhase with SymTransformer {
val pairs = classes.groupBy(_.symbol.name.stripModuleClassSuffix).asInstanceOf[Map[Name, List[TypeDef]]]

def rebuild(orig: TypeDef, newBody: List[Tree]): Tree = {
if (orig eq null) return EmptyTree

val staticFields = newBody.filter(x => x.isInstanceOf[ValDef] && x.symbol.hasAnnotation(defn.ScalaStaticAnnot)).asInstanceOf[List[ValDef]]
val newBodyWithStaticConstr =
if (staticFields.nonEmpty) {
Expand All @@ -61,21 +62,30 @@ class MoveStatics extends MiniPhase with SymTransformer {
assert(companion != module)
if (!module.symbol.is(Flags.Module)) move(companion, module)
else {
val allMembers =
(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)
val moduleTmpl = module.rhs.asInstanceOf[Template]
val companionTmpl = companion.rhs.asInstanceOf[Template]
val (staticDefs, remainingDefs) = moduleTmpl.body.partition {
case memberDef: MemberDef => memberDef.symbol.isScalaStatic
case _ => false
}

rebuild(companion, companionTmpl.body ++ staticDefs) :: rebuild(module, remainingDefs) :: Nil
}
}
val newPairs =
for ((name, classes) <- pairs)
yield
if (classes.tail.isEmpty)
if (classes.head.symbol.is(Flags.Module)) move(classes.head, null)
else List(rebuild(classes.head, classes.head.rhs.asInstanceOf[Template].body))
if (classes.tail.isEmpty) {
val classDef = classes.head
val tmpl = classDef.rhs.asInstanceOf[Template]
rebuild(classDef, tmpl.body) :: Nil
}
else move(classes.head, classes.tail.head)
Trees.flatten(newPairs.toList.flatten ++ others)
}
else trees
}

object MoveStatics {
val name: String = "moveStatic"
}
14 changes: 14 additions & 0 deletions tests/neg/i11100.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import scala.annotation.static

class C {
val a: Int = 3
class D
object D {
@static def foo: Int = a * a // error
}
}

@main
def Test =
val c = new C
println(c.D.foo)
25 changes: 12 additions & 13 deletions tests/run/statics.scala
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
import scala.annotation.static

class Foo{
class Foo {
class Bar {
def qwa =
Bar.field
Bar.field
// 0: invokestatic #31 // Method Foo$Bar$.field:()I
// 3: ireturn
}
object Bar {
@static
val field = 1
}
}

object Foo{
@static
def method = 1
object Foo {
@static
def method = 1

@static
val field = 2
@static
val field = 2

@static
var mutable = 3
@static
var mutable = 3

@static
def accessor = field
@static
def accessor = field
}

object Test {
Expand All @@ -34,7 +33,7 @@ object Test {
}
}

class WithLazies{
class WithLazies {
lazy val s = 1
// 98: getstatic #30 // Field WithLazies$.OFFSET$0:J
}

0 comments on commit d98b760

Please sign in to comment.