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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
package dotty.tools.dotc
package transform
import core._
import DenotTransformers._
import Phases.Phase
import Contexts.Context
import SymDenotations.SymDenotation
import Types._
import Symbols._
import SymUtils._
import Constants._
import ast.Trees._
import TreeTransforms._
import NameOps._
import Flags._
import Decorators._
/** Provides the implementations of all getters and setters, introducing
* fields to hold the value accessed by them.
* TODO: Make LazyVals a part of this phase?
*
* <accessor> <stable> <mods> def x(): T = e
* --> private val x: T = e
* <accessor> <stable> <mods> def x(): T = x
*
* <accessor> <mods> def x(): T = e
* --> private var x: T = e
* <accessor> <mods> def x(): T = x
*
* <accessor> <mods> def x_=(y: T): Unit = ()
* --> <accessor> <mods> def x_=(y: T): Unit = x = y
*/
class Memoize extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
import ast.tpd._
override def phaseName = "memoize"
/* Makes sure that, after getters and constructors gen, there doesn't
* exist non-deferred definitions that are not implemented. */
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
def errorLackImplementation(t: Tree) = {
val firstPhaseId = t.symbol.initial.validFor.firstPhaseId
val definingPhase = ctx.withPhase(firstPhaseId).phase.prev
throw new AssertionError(
i"Non-deferred definition introduced by $definingPhase lacks implementation: $t")
}
tree match {
case ddef: DefDef
if !ddef.symbol.is(Deferred) &&
!ddef.symbol.isConstructor && // constructors bodies are added later at phase Constructors
ddef.rhs == EmptyTree =>
errorLackImplementation(ddef)
case tdef: TypeDef
if tdef.symbol.isClass && !tdef.symbol.is(Deferred) && tdef.rhs == EmptyTree =>
errorLackImplementation(tdef)
case _ =>
}
super.checkPostCondition(tree)
}
/** Should run after mixin so that fields get generated in the
* class that contains the concrete getter rather than the trait
* that defines it.
*/
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val sym = tree.symbol
def newField = {
val fieldType =
if (sym.isGetter) sym.info.resultType
else /*sym.isSetter*/ sym.info.firstParamTypes.head
ctx.newSymbol(
owner = ctx.owner,
name = sym.name.asTermName.fieldName,
flags = Private | (if (sym is Stable) EmptyFlags else Mutable),
info = fieldType,
coord = tree.pos)
.withAnnotationsCarrying(sym, defn.FieldMetaAnnot)
.enteredAfter(thisTransform)
}
/** Can be used to filter annotations on getters and setters; not used yet */
def keepAnnotations(denot: SymDenotation, meta: ClassSymbol) = {
val cpy = sym.copySymDenotation()
cpy.filterAnnotations(_.symbol.derivesFrom(meta))
if (cpy.annotations ne denot.annotations) cpy.installAfter(thisTransform)
}
lazy val field = sym.field.orElse(newField).asTerm
def adaptToField(tree: Tree) =
if (tree.isEmpty) tree else tree.ensureConforms(field.info.widen)
val NoFieldNeeded = Lazy | Deferred | JavaDefined | (if (ctx.settings.YnoInline.value) EmptyFlags else Inline)
if (sym.is(Accessor, butNot = NoFieldNeeded))
if (sym.isGetter) {
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
if (isWildcardArg(rhs)) rhs = EmptyTree
val fieldDef = transformFollowing(ValDef(field, adaptToField(rhs)))
val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field))(ctx.withOwner(sym), info))
Thicket(fieldDef, getterDef)
} else if (sym.isSetter) {
if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs } // this is intended as an assertion
field.setFlag(Mutable) // necessary for vals mixed in from Scala2 traits
val initializer = Assign(ref(field), adaptToField(ref(tree.vparamss.head.head.symbol)))
cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(ctx.withOwner(sym), info))
}
else tree // curiously, some accessors from Scala2 have ' ' suffixes. They count as
// neither getters nor setters
else tree
}
}
|