@@ -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,43 @@ 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
+ *
75
86
* Conceptually, this is the second half of the previous mixin phase. It needs to run
76
87
* after erasure because it copies references to possibly private inner classes and objects
77
88
* into enclosing classes where they are not visible. This can only be done if all references
@@ -87,6 +98,8 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
87
98
override def transformSym (sym : SymDenotation )(implicit ctx : Context ): SymDenotation =
88
99
if (sym.is(Accessor , butNot = Deferred ) && sym.owner.is(Trait ))
89
100
sym.copySymDenotation(initFlags = sym.flags | Deferred ).ensureNotPrivate
101
+ else if (sym.isConstructor && sym.owner.is(Trait ) && sym.info.firstParamTypes.nonEmpty)
102
+ sym.copySymDenotation(info = MethodType (Nil , sym.info.resultType))
90
103
else
91
104
sym
92
105
@@ -131,15 +144,22 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
131
144
}) ++ initBuf
132
145
}
133
146
134
- def transformSuper (tree : Tree ): Tree = {
147
+ /** Map constructor call to a pair of a supercall and a list of arguments
148
+ * to be used as initializers of trait parameters if the target of the call
149
+ * is a trait.
150
+ */
151
+ def transformConstructor (tree : Tree ): (Tree , List [Tree ]) = {
135
152
val Apply (sel @ Select (New (_), nme.CONSTRUCTOR ), args) = tree
136
- superRef(tree.symbol, tree.pos).appliedToArgs(args)
153
+ val (callArgs, initArgs) = if (tree.symbol.owner.is(Trait )) (Nil , args) else (args, Nil )
154
+ (superRef(tree.symbol, tree.pos).appliedToArgs(callArgs), initArgs)
137
155
}
138
156
139
- val superCalls = (
157
+ val superCallsAndArgs = (
140
158
for (p <- impl.parents if p.symbol.isConstructor)
141
- yield p.symbol.owner -> transformSuper (p)
159
+ yield p.symbol.owner -> transformConstructor (p)
142
160
).toMap
161
+ val superCalls = superCallsAndArgs.mapValues(_._1)
162
+ val initArgs = superCallsAndArgs.mapValues(_._2)
143
163
144
164
def superCallOpt (baseCls : Symbol ): List [Tree ] = superCalls.get(baseCls) match {
145
165
case Some (call) =>
@@ -155,12 +175,31 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
155
175
def wasDeferred (sym : Symbol ) =
156
176
ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
157
177
158
- def traitInits (mixin : ClassSymbol ): List [Tree ] =
178
+ def traitInits (mixin : ClassSymbol ): List [Tree ] = {
179
+ var argNum = 0
180
+ def nextArgument () = initArgs.get(mixin) match {
181
+ case Some (arguments) =>
182
+ try arguments(argNum) finally argNum += 1
183
+ case None =>
184
+ val (msg, pos) = impl.parents.find(_.tpe.typeSymbol == mixin) match {
185
+ case Some (parent) => (" lacks argument list" , parent.pos)
186
+ case None =>
187
+ (""" is indirectly implemented,
188
+ |needs to be implemented directly so that arguments can be passed""" .stripMargin,
189
+ cls.pos)
190
+ }
191
+ ctx.error(i " parameterized $mixin $msg" , pos)
192
+ EmptyTree
193
+ }
159
194
for (getter <- mixin.info.decls.filter(getr => getr.isGetter && ! wasDeferred(getr)).toList) yield {
160
195
val isScala2x = mixin.is(Scala2x )
161
196
def default = Underscore (getter.info.resultType)
162
197
def initial = transformFollowing(superRef(initializer(getter)).appliedToNone)
163
- if (isCurrent(getter) || getter.is(ExpandedName ))
198
+ if (isCurrent(getter) || getter.is(ExpandedName )) {
199
+ val rhs =
200
+ if (getter.is(ParamAccessor )) nextArgument()
201
+ else if (isScala2x) Underscore (getter.info.resultType)
202
+ else transformFollowing(superRef(initializer(getter)).appliedToNone)
164
203
// transformFollowing call is needed to make memoize & lazy vals run
165
204
transformFollowing(
166
205
DefDef (implementation(getter.asTerm),
@@ -178,12 +217,17 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
178
217
else if (isScala2x) EmptyTree
179
218
else initial
180
219
}
220
+ }
181
221
182
222
def setters (mixin : ClassSymbol ): List [Tree ] =
183
223
for (setter <- mixin.info.decls.filter(setr => setr.isSetter && ! wasDeferred(setr)).toList)
184
224
yield DefDef (implementation(setter.asTerm), unitLiteral.withPos(cls.pos))
185
225
186
226
cpy.Template (impl)(
227
+ constr =
228
+ if (cls.is(Trait ) && impl.constr.vparamss.flatten.nonEmpty)
229
+ cpy.DefDef (impl.constr)(vparamss = Nil :: Nil )
230
+ else impl.constr,
187
231
parents = impl.parents.map(p => TypeTree (p.tpe).withPos(p.pos)),
188
232
body =
189
233
if (cls is Trait ) traitDefs(impl.body)
0 commit comments