Skip to content

Commit d98b760

Browse files
authored
Merge pull request #11126 from dotty-staging/fix-8022
Fix #8022: Refactor MoveStatics
2 parents b4d0cd4 + cdebeb6 commit d98b760

File tree

5 files changed

+65
-59
lines changed

5 files changed

+65
-59
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: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
1-
package dotty.tools.dotc.transform
1+
package dotty.tools.dotc
2+
package transform
23

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
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._
1516

16-
object MoveStatics {
17-
val name: String = "moveStatic"
18-
}
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 =
@@ -38,8 +41,6 @@ class MoveStatics extends MiniPhase with SymTransformer {
3841
val pairs = classes.groupBy(_.symbol.name.stripModuleClassSuffix).asInstanceOf[Map[Name, List[TypeDef]]]
3942

4043
def rebuild(orig: TypeDef, newBody: List[Tree]): Tree = {
41-
if (orig eq null) return EmptyTree
42-
4344
val staticFields = newBody.filter(x => x.isInstanceOf[ValDef] && x.symbol.hasAnnotation(defn.ScalaStaticAnnot)).asInstanceOf[List[ValDef]]
4445
val newBodyWithStaticConstr =
4546
if (staticFields.nonEmpty) {
@@ -61,21 +62,30 @@ class MoveStatics extends MiniPhase with SymTransformer {
6162
assert(companion != module)
6263
if (!module.symbol.is(Flags.Module)) move(companion, module)
6364
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)
65+
val moduleTmpl = module.rhs.asInstanceOf[Template]
66+
val companionTmpl = companion.rhs.asInstanceOf[Template]
67+
val (staticDefs, remainingDefs) = moduleTmpl.body.partition {
68+
case memberDef: MemberDef => memberDef.symbol.isScalaStatic
69+
case _ => false
70+
}
71+
72+
rebuild(companion, companionTmpl.body ++ staticDefs) :: rebuild(module, remainingDefs) :: Nil
6973
}
7074
}
7175
val newPairs =
7276
for ((name, classes) <- pairs)
7377
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))
78+
if (classes.tail.isEmpty) {
79+
val classDef = classes.head
80+
val tmpl = classDef.rhs.asInstanceOf[Template]
81+
rebuild(classDef, tmpl.body) :: Nil
82+
}
7783
else move(classes.head, classes.tail.head)
7884
Trees.flatten(newPairs.toList.flatten ++ others)
7985
}
8086
else trees
8187
}
88+
89+
object MoveStatics {
90+
val name: String = "moveStatic"
91+
}

tests/neg/i11100.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.annotation.static
2+
3+
class C {
4+
val a: Int = 3
5+
class D
6+
object D {
7+
@static def foo: Int = a * a // error
8+
}
9+
}
10+
11+
@main
12+
def Test =
13+
val c = new C
14+
println(c.D.foo)

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)