1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
package dotty.tools.dotc
package transform
import core._
import Names._
import StdNames.nme
import Types._
import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer}
import ast.Trees._
import Flags._
import Contexts.Context
import Symbols._
import Constants._
import Denotations._, SymDenotations._
import Decorators.StringInterpolators
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Annotations.ConcreteAnnotation
import scala.collection.mutable
import DenotTransformers._
import Names.Name
import NameOps._
import Decorators._
import TypeUtils._
/** A transformer that check that requirements of Static fields\methods are implemented:
* 1. Only objects can have members annotated with `@static`
* 2. The fields annotated with `@static` should preceed any non-`@static` fields.
* This ensures that we do not introduce surprises for users in initialization order.
* 3. If a member `foo` of an `object C` is annotated with `@static`,
* the companion class `C` is not allowed to define term members with name `foo`.
* 4. If a member `foo` of an `object C` is annotated with `@static`, the companion class `C`
* is not allowed to inherit classes that define a term member with name `foo`.
* 5. Only `@static` methods and vals are supported in companions of traits.
* Java8 supports those, but not vars, and JavaScript does not have interfaces at all.
*/
class CheckStatic extends MiniPhaseTransform { thisTransformer =>
import ast.tpd._
override def phaseName = "elimRepeated"
def check(tree: tpd.DefTree)(implicit ctx: Context) = {
}
override def transformTemplate(tree: tpd.Template)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
val defns = tree.body.collect{case t: ValOrDefDef => t}
var hadNonStaticField = false
for(defn <- defns) {
if (defn.symbol.hasAnnotation(ctx.definitions.ScalaStaticAnnot)) {
if(!ctx.owner.is(Module)) {
ctx.error("@static fields are only allowed inside objects", defn.pos)
}
if (defn.isInstanceOf[ValDef] && hadNonStaticField) {
ctx.error("@static fields should preceed non-static ones", defn.pos)
}
val companion = ctx.owner.companionClass
if (!companion.exists) {
ctx.error("object that conatin @static members should have companion class", defn.pos)
}
val clashes = companion.asClass.membersNamed(defn.name)
if (clashes.exists) {
ctx.error("companion classes cannot define members with same name as @static member", defn.pos)
}
if (defn.symbol.is(Flags.Mutable) && companion.is(Flags.Trait)) {
ctx.error("Companions of traits cannot define mutable @static fields")
}
} else hadNonStaticField = hadNonStaticField || defn.isInstanceOf[ValDef]
}
tree
}
override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
if (tree.symbol.hasAnnotation(defn.ScalaStaticAnnot))
ref(tree.symbol)
else tree
}
}
|