@@ -20,7 +20,7 @@ import collection.mutable
20
20
21
21
/** This phase performs the following transformations:
22
22
*
23
- * 1. (done in `traitDefs`) Map every concrete trait getter
23
+ * 1. (done in `traitDefs` and `transformSym `) Map every concrete trait getter
24
24
*
25
25
* <mods> def x(): T = expr
26
26
*
@@ -46,32 +46,45 @@ import collection.mutable
46
46
* For every trait M directly implemented by the class (see SymUtils.mixin), in
47
47
* reverse linearization order, add the following definitions to C:
48
48
*
49
- * 3.1 (done in `traitInits`) For every concrete trait getter `<mods> def x(): T` in M,
50
- * in order of textual occurrence, produce the following:
49
+ * 3.1 (done in `traitInits`) For every parameter accessor `<mods> def x(): T` in M,
50
+ * in order of textual occurrence, add
51
51
*
52
- * 3.1.1 If `x` is also a member of `C`, and M is a Dotty trait:
52
+ * <mods> def x() = e
53
+ *
54
+ * where `e` is the constructor argument in C that corresponds to `x`. Issue
55
+ * an error if no such argument exists.
56
+ *
57
+ * 3.2 (done in `traitInits`) For every concrete trait getter `<mods> def x(): T` in M
58
+ * which is not a parameter accessor, in order of textual occurrence, produce the following:
59
+ *
60
+ * 3.2.1 If `x` is also a member of `C`, and M is a Dotty trait:
53
61
*
54
62
* <mods> def x(): T = super[M].initial$x()
55
63
*
56
- * 3.1 .2 If `x` is also a member of `C`, and M is a Scala 2.x trait:
64
+ * 3.2 .2 If `x` is also a member of `C`, and M is a Scala 2.x trait:
57
65
*
58
66
* <mods> def x(): T = _
59
67
*
60
- * 3.1 .3 If `x` is not a member of `C`, and M is a Dotty trait:
68
+ * 3.2 .3 If `x` is not a member of `C`, and M is a Dotty trait:
61
69
*
62
70
* super[M].initial$x()
63
71
*
64
- * 3.1 .4 If `x` is not a member of `C`, and M is a Scala2.x trait, nothing gets added.
72
+ * 3.2 .4 If `x` is not a member of `C`, and M is a Scala2.x trait, nothing gets added.
65
73
*
66
74
*
67
- * 3.2 (done in `superCallOpt`) The call:
75
+ * 3.3 (done in `superCallOpt`) The call:
68
76
*
69
77
* super[M].<init>
70
78
*
71
- * 3.3 (done in `setters`) For every concrete setter `<mods> def x_=(y: T)` in M:
79
+ * 3.4 (done in `setters`) For every concrete setter `<mods> def x_=(y: T)` in M:
72
80
*
73
81
* <mods> def x_=(y: T) = ()
74
82
*
83
+ * 4. (done in `transformTemplate` and `transformSym`) Drop all parameters from trait
84
+ * constructors.
85
+ *
86
+ * 5. (done in `transformSym`) Drop ParamAccessor flag from all parameter accessors in traits.
87
+ *
75
88
* Conceptually, this is the second half of the previous mixin phase. It needs to run
76
89
* after erasure because it copies references to possibly private inner classes and objects
77
90
* into enclosing classes where they are not visible. This can only be done if all references
@@ -86,7 +99,9 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
86
99
87
100
override def transformSym (sym : SymDenotation )(implicit ctx : Context ): SymDenotation =
88
101
if (sym.is(Accessor , butNot = Deferred ) && sym.owner.is(Trait ))
89
- sym.copySymDenotation(initFlags = sym.flags | Deferred ).ensureNotPrivate
102
+ sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred ).ensureNotPrivate
103
+ else if (sym.isConstructor && sym.owner.is(Trait ) && sym.info.firstParamTypes.nonEmpty)
104
+ sym.copySymDenotation(info = MethodType (Nil , sym.info.resultType))
90
105
else
91
106
sym
92
107
@@ -111,7 +126,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
111
126
def traitDefs (stats : List [Tree ]): List [Tree ] = {
112
127
val initBuf = new mutable.ListBuffer [Tree ]
113
128
stats.flatMap({
114
- case stat : DefDef if stat.symbol.isGetter && ! stat.rhs.isEmpty && ! stat.symbol.is(Flags .Lazy ) =>
129
+ case stat : DefDef if stat.symbol.isGetter && ! stat.rhs.isEmpty && ! stat.symbol.is(Flags .Lazy ) =>
115
130
// make initializer that has all effects of previous getter,
116
131
// replace getter rhs with empty tree.
117
132
val vsym = stat.symbol
@@ -131,15 +146,22 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
131
146
}) ++ initBuf
132
147
}
133
148
134
- def transformSuper (tree : Tree ): Tree = {
149
+ /** Map constructor call to a pair of a supercall and a list of arguments
150
+ * to be used as initializers of trait parameters if the target of the call
151
+ * is a trait.
152
+ */
153
+ def transformConstructor (tree : Tree ): (Tree , List [Tree ]) = {
135
154
val Apply (sel @ Select (New (_), nme.CONSTRUCTOR ), args) = tree
136
- superRef(tree.symbol, tree.pos).appliedToArgs(args)
155
+ val (callArgs, initArgs) = if (tree.symbol.owner.is(Trait )) (Nil , args) else (args, Nil )
156
+ (superRef(tree.symbol, tree.pos).appliedToArgs(callArgs), initArgs)
137
157
}
138
158
139
- val superCalls = (
159
+ val superCallsAndArgs = (
140
160
for (p <- impl.parents if p.symbol.isConstructor)
141
- yield p.symbol.owner -> transformSuper (p)
161
+ yield p.symbol.owner -> transformConstructor (p)
142
162
).toMap
163
+ val superCalls = superCallsAndArgs.mapValues(_._1)
164
+ val initArgs = superCallsAndArgs.mapValues(_._2)
143
165
144
166
def superCallOpt (baseCls : Symbol ): List [Tree ] = superCalls.get(baseCls) match {
145
167
case Some (call) =>
@@ -155,35 +177,63 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
155
177
def wasDeferred (sym : Symbol ) =
156
178
ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
157
179
158
- def traitInits (mixin : ClassSymbol ): List [Tree ] =
180
+ def traitInits (mixin : ClassSymbol ): List [Tree ] = {
181
+ var argNum = 0
182
+ def nextArgument () = initArgs.get(mixin) match {
183
+ case Some (arguments) =>
184
+ try arguments(argNum) finally argNum += 1
185
+ case None =>
186
+ val (msg, pos) = impl.parents.find(_.tpe.typeSymbol == mixin) match {
187
+ case Some (parent) => (" lacks argument list" , parent.pos)
188
+ case None =>
189
+ (""" is indirectly implemented,
190
+ |needs to be implemented directly so that arguments can be passed""" .stripMargin,
191
+ cls.pos)
192
+ }
193
+ ctx.error(i " parameterized $mixin $msg" , pos)
194
+ EmptyTree
195
+ }
196
+
159
197
for (getter <- mixin.info.decls.filter(getr => getr.isGetter && ! wasDeferred(getr)).toList) yield {
160
198
val isScala2x = mixin.is(Scala2x )
161
199
def default = Underscore (getter.info.resultType)
162
200
def initial = transformFollowing(superRef(initializer(getter)).appliedToNone)
163
- if (isCurrent(getter) || getter.is(ExpandedName ))
201
+
202
+ /** A call to the implementation of `getter` in `mixin`'s implementation class */
203
+ def lazyGetterCall = {
204
+ def canbeImplClassGetter (sym : Symbol ) = sym.info.firstParamTypes match {
205
+ case t :: Nil => t.isDirectRef(mixin)
206
+ case _ => false
207
+ }
208
+ val implClassGetter = mixin.implClass.info.nonPrivateDecl(getter.name)
209
+ .suchThat(canbeImplClassGetter).symbol
210
+ ref(mixin.implClass).select(implClassGetter).appliedTo(This (cls))
211
+ }
212
+
213
+ if (isCurrent(getter) || getter.is(ExpandedName )) {
214
+ val rhs =
215
+ if (ctx.atPhase(thisTransform)(implicit ctx => getter.is(ParamAccessor ))) nextArgument()
216
+ else if (isScala2x)
217
+ if (getter.is(Lazy )) lazyGetterCall
218
+ else Underscore (getter.info.resultType)
219
+ else transformFollowing(superRef(initializer(getter)).appliedToNone)
164
220
// transformFollowing call is needed to make memoize & lazy vals run
165
- transformFollowing(
166
- DefDef (implementation(getter.asTerm),
167
- if (isScala2x) {
168
- if (getter.is(Flags .Lazy )) { // lazy vals need to have a rhs that will be the lazy initializer
169
- val sym = mixin.implClass.info.nonPrivateDecl(getter.name).suchThat(_.info.paramTypess match {
170
- case List (List (t : TypeRef )) => t.isDirectRef(mixin)
171
- case _ => false
172
- }).symbol // lazy val can be overloaded
173
- ref(mixin.implClass).select(sym).appliedTo(This (ctx.owner.asClass))
174
- }
175
- else default
176
- } else initial)
177
- )
221
+ transformFollowing(DefDef (implementation(getter.asTerm), rhs))
222
+ }
178
223
else if (isScala2x) EmptyTree
179
224
else initial
180
225
}
226
+ }
181
227
182
228
def setters (mixin : ClassSymbol ): List [Tree ] =
183
229
for (setter <- mixin.info.decls.filter(setr => setr.isSetter && ! wasDeferred(setr)).toList)
184
230
yield DefDef (implementation(setter.asTerm), unitLiteral.withPos(cls.pos))
185
231
186
232
cpy.Template (impl)(
233
+ constr =
234
+ if (cls.is(Trait ) && impl.constr.vparamss.flatten.nonEmpty)
235
+ cpy.DefDef (impl.constr)(vparamss = Nil :: Nil )
236
+ else impl.constr,
187
237
parents = impl.parents.map(p => TypeTree (p.tpe).withPos(p.pos)),
188
238
body =
189
239
if (cls is Trait ) traitDefs(impl.body)
0 commit comments