Skip to content

Commit ce8eac1

Browse files
committed
Fix #8022: Refactor MoveStatics
We still keep two phases, but the code is simplified. We cannot merge MoveStatics with CheckStatic because the early phases are not able to handle static calls, thus it has to be at the end of the pipeline. Meanwhile, we want checks to happen as early as possible, thus CheckStatic has to be in the beginning of the pipeline.
1 parent 3536773 commit ce8eac1

File tree

4 files changed

+70
-60
lines changed

4 files changed

+70
-60
lines changed

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1943,7 +1943,7 @@ import transform.SymUtils._
19431943
}
19441944

19451945
class StaticFieldsOnlyAllowedInObjects(member: Symbol)(using Context) extends SyntaxMsg(StaticFieldsOnlyAllowedInObjectsID) {
1946-
def msg = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}."
1946+
def msg = em"${hl("@static")} $member in ${member.owner} must be defined inside a static ${hl("object")}."
19471947
def explain =
19481948
em"${hl("@static")} members are only allowed inside objects."
19491949
}

compiler/src/dotty/tools/dotc/transform/CheckStatic.scala

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class CheckStatic extends MiniPhase {
3434
var hadNonStaticField = false
3535
for (defn <- defns)
3636
if (defn.symbol.isScalaStatic) {
37-
if (!ctx.owner.is(Module))
37+
if (!ctx.owner.isStaticOwner)
3838
report.error(StaticFieldsOnlyAllowedInObjects(defn.symbol), defn.srcPos)
3939
defn.symbol.resetFlag(JavaStatic)
4040

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

6060
tree
6161
}
62-
63-
override def transformSelect(tree: tpd.Select)(using Context): tpd.Tree =
64-
if (tree.symbol.hasAnnotation(defn.ScalaStaticAnnot)) {
65-
val symbolWhitelist = tree.symbol.ownersIterator.flatMap(x => if (x.is(Flags.Module)) List(x, x.companionModule) else List(x)).toSet
66-
def isSafeQual(t: Tree): Boolean = // follow the desugared paths created by typer
67-
t match {
68-
case t: This => true
69-
case t: Select => isSafeQual(t.qualifier) && symbolWhitelist.contains(t.symbol)
70-
case t: Ident => symbolWhitelist.contains(t.symbol)
71-
case t: Block => t.stats.forall(tpd.isPureExpr) && isSafeQual(t.expr)
72-
case _ => false
73-
}
74-
if (isSafeQual(tree.qualifier))
75-
ref(tree.symbol)
76-
else tree
77-
}
78-
else tree
7962
}
8063

8164
object CheckStatic {
Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
1-
package dotty.tools.dotc.transform
2-
3-
import dotty.tools.dotc.ast.{Trees, tpd}
4-
import dotty.tools.dotc.core.Annotations.Annotation
5-
import dotty.tools.dotc.core.Contexts._
6-
import dotty.tools.dotc.core.DenotTransformers.SymTransformer
7-
import dotty.tools.dotc.core.SymDenotations.SymDenotation
8-
import dotty.tools.dotc.core.NameOps._
9-
import dotty.tools.dotc.core.Flags
10-
import dotty.tools.dotc.core.Names.Name
11-
import dotty.tools.dotc.core.StdNames.nme
12-
import dotty.tools.dotc.core.Symbols._
13-
import dotty.tools.dotc.core.Types.MethodType
14-
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
1+
package dotty.tools.dotc
2+
package transform
153

16-
object MoveStatics {
17-
val name: String = "moveStatic"
18-
}
4+
import core._
5+
import Flags._
6+
import Contexts._
7+
import Symbols._
8+
import Decorators._
9+
import DenotTransformers.SymTransformer
10+
import Types.MethodType
11+
import Annotations.Annotation
12+
import SymDenotations.SymDenotation
13+
import Names.Name
14+
import StdNames.nme
15+
import NameOps._
16+
17+
import reporting._
18+
import ast._
19+
20+
import SymUtils._
21+
import MegaPhase._
1922

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

23-
import tpd._
2427
override def phaseName: String = MoveStatics.name
2528

2629
def transformSym(sym: SymDenotation)(using Context): SymDenotation =
@@ -32,14 +35,30 @@ class MoveStatics extends MiniPhase with SymTransformer {
3235
}
3336
else sym
3437

38+
override def transformSelect(tree: tpd.Select)(using Context): tpd.Tree =
39+
if (tree.symbol.hasAnnotation(defn.ScalaStaticAnnot)) {
40+
def isSafeQual(t: Tree): Boolean = // follow the desugared paths created by typer
41+
t match {
42+
case t: This => true
43+
case t: Select => isSafeQual(t.qualifier)
44+
case t: Block => t.stats.forall(tpd.isPureExpr) && isSafeQual(t.expr)
45+
case _ => false
46+
}
47+
48+
if (isSafeQual(tree.qualifier))
49+
ref(tree.symbol)
50+
else
51+
Block(tree.qualifier :: Nil, ref(tree.symbol))
52+
}
53+
else tree
54+
55+
3556
override def transformStats(trees: List[Tree])(using Context): List[Tree] =
3657
if (ctx.owner.is(Flags.Package)) {
3758
val (classes, others) = trees.partition(x => x.isInstanceOf[TypeDef] && x.symbol.isClass)
3859
val pairs = classes.groupBy(_.symbol.name.stripModuleClassSuffix).asInstanceOf[Map[Name, List[TypeDef]]]
3960

4061
def rebuild(orig: TypeDef, newBody: List[Tree]): Tree = {
41-
if (orig eq null) return EmptyTree
42-
4362
val staticFields = newBody.filter(x => x.isInstanceOf[ValDef] && x.symbol.hasAnnotation(defn.ScalaStaticAnnot)).asInstanceOf[List[ValDef]]
4463
val newBodyWithStaticConstr =
4564
if (staticFields.nonEmpty) {
@@ -61,21 +80,30 @@ class MoveStatics extends MiniPhase with SymTransformer {
6180
assert(companion != module)
6281
if (!module.symbol.is(Flags.Module)) move(companion, module)
6382
else {
64-
val allMembers =
65-
(if (companion != null) {companion.rhs.asInstanceOf[Template].body} else Nil) ++
66-
module.rhs.asInstanceOf[Template].body
67-
val (newModuleBody, newCompanionBody) = allMembers.partition(x => {assert(x.symbol.exists); x.symbol.owner == module.symbol})
68-
Trees.flatten(rebuild(companion, newCompanionBody) :: rebuild(module, newModuleBody) :: Nil)
83+
val moduleTmpl = module.rhs.asInstanceOf[Template]
84+
val companionTmpl = companion.rhs.asInstanceOf[Template]
85+
val (staticDefs, remainingDefs) = moduleTmpl.body.partition {
86+
case memberDef: MemberDef => memberDef.symbol.isScalaStatic
87+
case _ => false
88+
}
89+
90+
rebuild(companion, companionTmpl.body ++ staticDefs) :: rebuild(module, remainingDefs) :: Nil
6991
}
7092
}
7193
val newPairs =
7294
for ((name, classes) <- pairs)
7395
yield
74-
if (classes.tail.isEmpty)
75-
if (classes.head.symbol.is(Flags.Module)) move(classes.head, null)
76-
else List(rebuild(classes.head, classes.head.rhs.asInstanceOf[Template].body))
96+
if (classes.tail.isEmpty) {
97+
val classDef = classes.head
98+
val tmpl = classDef.rhs.asInstanceOf[Template]
99+
rebuild(classDef, tmpl.body) :: Nil
100+
}
77101
else move(classes.head, classes.tail.head)
78102
Trees.flatten(newPairs.toList.flatten ++ others)
79103
}
80104
else trees
81105
}
106+
107+
object MoveStatics {
108+
val name: String = "moveStatic"
109+
}

tests/run/statics.scala

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
import scala.annotation.static
22

3-
class Foo{
3+
class Foo {
44
class Bar {
55
def qwa =
6-
Bar.field
6+
Bar.field
77
// 0: invokestatic #31 // Method Foo$Bar$.field:()I
88
// 3: ireturn
99
}
1010
object Bar {
11-
@static
1211
val field = 1
1312
}
1413
}
1514

16-
object Foo{
17-
@static
18-
def method = 1
15+
object Foo {
16+
@static
17+
def method = 1
1918

20-
@static
21-
val field = 2
19+
@static
20+
val field = 2
2221

23-
@static
24-
var mutable = 3
22+
@static
23+
var mutable = 3
2524

26-
@static
27-
def accessor = field
25+
@static
26+
def accessor = field
2827
}
2928

3029
object Test {
@@ -34,7 +33,7 @@ object Test {
3433
}
3534
}
3635

37-
class WithLazies{
36+
class WithLazies {
3837
lazy val s = 1
3938
// 98: getstatic #30 // Field WithLazies$.OFFSET$0:J
4039
}

0 commit comments

Comments
 (0)