1
- package dotty .tools .dotc
1
+ package dotty .tools
2
+ package dotc
2
3
package transform
3
4
4
5
import core ._
@@ -194,7 +195,24 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
194
195
for (p <- impl.parents; constr = stripBlock(p).symbol if constr.isConstructor)
195
196
yield constr.owner -> transformConstructor(p)
196
197
).toMap
197
- val superCalls = superCallsAndArgs.transform((_, v) => v._1)
198
+
199
+ /** Definitions in a parent trait constructor call (these can arise
200
+ * due to reorderings with named and/or default parameters).
201
+ */
202
+ def prefix (tree : Tree ): List [Tree ] =
203
+ if stripBlock(tree).symbol.owner.is(Trait ) then
204
+ tree match
205
+ case Block (stats, expr) => stats ::: prefix(expr)
206
+ case _ => Nil
207
+ else Nil
208
+
209
+ /** the proper trait parent constructor call, without any preceding val defs */
210
+ def properCall (tree : Tree ): Tree =
211
+ val call = stripBlock(tree)
212
+ if call.symbol.owner.is(Trait ) then call else tree
213
+
214
+ val prefixes = superCallsAndArgs.transform((_, v) => prefix(v._1))
215
+ val superCalls = superCallsAndArgs.transform((_, v) => properCall(v._1))
198
216
val initArgs = superCallsAndArgs.transform((_, v) => v._2)
199
217
200
218
def superCallOpt (baseCls : Symbol ): List [Tree ] = superCalls.get(baseCls) match {
@@ -211,6 +229,38 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
211
229
def wasOneOf (sym : Symbol , flags : FlagSet ) =
212
230
ctx.atPhase(thisPhase) { sym.isOneOf(flags) }
213
231
232
+ /** The prefix definitions of a mixin parent constructor, lifted
233
+ * to the enclosing class.
234
+ */
235
+ def traitConstrPrefix (mixin : ClassSymbol ): List [Tree ] =
236
+ prefixes.get(mixin) match
237
+ case Some (stats) =>
238
+ stats.map {
239
+ case stat : ValDef =>
240
+ stat.symbol.copySymDenotation(
241
+ owner = cls,
242
+ initFlags = stat.symbol.flags | PrivateLocal
243
+ ).installAfter(thisPhase)
244
+ stat.symbol.enteredAfter(thisPhase)
245
+ stat
246
+ }
247
+ case _ =>
248
+ Nil
249
+
250
+ /** Adapt tree so that references to valdefs that are lifted to the
251
+ * class now use `this` as a prefix
252
+ */
253
+ def adaptToPrefix (stat : Tree , prefixSyms : List [Symbol ]) =
254
+ if prefixSyms.isEmpty then stat
255
+ else
256
+ val m = new TreeMap :
257
+ override def transform (tree : Tree )(using Context ) = tree match
258
+ case tree : Ident if prefixSyms.contains(tree.symbol) =>
259
+ This (cls).select(tree.symbol).withSpan(tree.span)
260
+ case _ =>
261
+ super .transform(tree)
262
+ m.transform(stat)
263
+
214
264
def traitInits (mixin : ClassSymbol ): List [Tree ] = {
215
265
var argNum = 0
216
266
def nextArgument () = initArgs.get(mixin) match {
@@ -275,7 +325,11 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
275
325
if (cls.is(Trait )) traitDefs(impl.body)
276
326
else if (! cls.isPrimitiveValueClass) {
277
327
val mixInits = mixins.flatMap { mixin =>
278
- flatten(traitInits(mixin)) ::: superCallOpt(mixin) ::: setters(mixin) ::: mixinForwarders(mixin)
328
+ val prefix = traitConstrPrefix(mixin)
329
+ val prefixSyms = prefix.map(_.symbol)
330
+ val initsAndCall = (flatten(traitInits(mixin)) ::: superCallOpt(mixin))
331
+ .map(adaptToPrefix(_, prefixSyms))
332
+ prefix ::: initsAndCall ::: setters(mixin) ::: mixinForwarders(mixin)
279
333
}
280
334
superCallOpt(superCls) ::: mixInits ::: impl.body
281
335
}
0 commit comments