@@ -177,98 +177,61 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
177177 }) ++ initBuf
178178 }
179179
180- /** Map constructor call to a pair of a supercall and a list of arguments
181- * to be used as initializers of trait parameters if the target of the call
182- * is a trait.
180+ /** Map constructor call to a triple of a supercall, and if the target
181+ * is a trait
182+ * - a list of val defs used in arguments (these can arise
183+ * due to reorderings with named and/or default parameters).
184+ * - a list of arguments to be used as initializers of trait parameters
183185 */
184- def transformConstructor (tree : Tree ): (Tree , List [Tree ]) = tree match {
186+ def transformConstructor (tree : Tree ): (Tree , List [Tree ], List [ Tree ] ) = tree match {
185187 case Block (stats, expr) =>
186- val (scall, inits) = transformConstructor(expr)
187- (cpy.Block (tree)(stats, scall), inits)
188+ val (scall, inits, args) = transformConstructor(expr)
189+ if args.isEmpty then
190+ (cpy.Block (tree)(stats, scall), inits, args)
191+ else // it's a trait constructor with parameters, lift all prefix statements to class context
192+ // so that they precede argument definitions.
193+ stats.foreach {
194+ case stat : ValDef =>
195+ stat.symbol.copySymDenotation(
196+ owner = cls,
197+ initFlags = stat.symbol.flags | PrivateLocal
198+ ).installAfter(thisPhase)
199+ stat.symbol.enteredAfter(thisPhase)
200+ }
201+ (scall, stats ::: inits, args)
188202 case _ =>
189203 val Apply (sel @ Select (New (_), nme.CONSTRUCTOR ), args) = tree
190204 val (callArgs, initArgs) = if (tree.symbol.owner.is(Trait )) (Nil , args) else (args, Nil )
191- (superRef(tree.symbol, tree.span).appliedToArgs(callArgs), initArgs)
205+ (superRef(tree.symbol, tree.span).appliedToArgs(callArgs), Nil , initArgs)
192206 }
193207
194- val superCallsAndArgs = (
208+ val superCallsAndArgs : Map [ Symbol , ( Tree , List [ Tree ], List [ Tree ])] = (
195209 for (p <- impl.parents; constr = stripBlock(p).symbol if constr.isConstructor)
196210 yield constr.owner -> transformConstructor(p)
197211 ).toMap
198212
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))
216- val initArgs = superCallsAndArgs.transform((_, v) => v._2)
217-
218- def superCallOpt (baseCls : Symbol ): List [Tree ] = superCalls.get(baseCls) match {
219- case Some (call) =>
213+ def superCallOpt (baseCls : Symbol ): List [Tree ] =
214+ superCallsAndArgs.get(baseCls) match
215+ case Some ((call, _, _)) =>
220216 if (defn.NotRuntimeClasses .contains(baseCls) || baseCls.isAllOf(NoInitsTrait )) Nil
221217 else call :: Nil
222218 case None =>
223- if (baseCls.isAllOf(NoInitsTrait ) || defn.NoInitClasses .contains(baseCls) || defn.isFunctionClass(baseCls)) Nil
219+ if baseCls.isAllOf(NoInitsTrait ) || defn.NoInitClasses .contains(baseCls) || defn.isFunctionClass(baseCls) then
220+ Nil
224221 else
225222 // println(i"synth super call ${baseCls.primaryConstructor}: ${baseCls.primaryConstructor.info}")
226223 transformFollowingDeep(superRef(baseCls.primaryConstructor).appliedToNone) :: Nil
227- }
228224
229225 def wasOneOf (sym : Symbol , flags : FlagSet ) =
230226 ctx.atPhase(thisPhase) { sym.isOneOf(flags) }
231227
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-
264228 def traitInits (mixin : ClassSymbol ): List [Tree ] = {
265- var argNum = 0
266- def nextArgument () = initArgs.get(mixin) match {
267- case Some (arguments) =>
268- val result = arguments(argNum)
269- argNum += 1
270- result
271- case None =>
229+ val argsIt = superCallsAndArgs.get(mixin) match
230+ case Some ((_, _, args)) => args.iterator
231+ case _ => Iterator .empty
232+ def nextArgument () =
233+ if argsIt.hasNext then argsIt.next
234+ else
272235 assert(
273236 impl.parents.forall(_.tpe.typeSymbol != mixin),
274237 i " missing parameters for $mixin from $impl should have been caught in typer " )
@@ -277,7 +240,6 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
277240 |needs to be implemented directly so that arguments can be passed """ ,
278241 cls.sourcePos)
279242 EmptyTree
280- }
281243
282244 for (getter <- mixin.info.decls.toList if getter.isGetter && ! wasOneOf(getter, Deferred )) yield {
283245 val isScala2x = mixin.is(Scala2x )
@@ -325,13 +287,18 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
325287 if (cls.is(Trait )) traitDefs(impl.body)
326288 else if (! cls.isPrimitiveValueClass) {
327289 val mixInits = mixins.flatMap { 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)
290+ val prefix = superCallsAndArgs.get(mixin) match
291+ case Some ((_, inits, _)) => inits
292+ case _ => Nil
293+ prefix
294+ ::: flatten(traitInits(mixin))
295+ ::: superCallOpt(mixin)
296+ ::: setters(mixin)
297+ ::: mixinForwarders(mixin)
333298 }
334- superCallOpt(superCls) ::: mixInits ::: impl.body
299+ superCallOpt(superCls)
300+ ::: mixInits
301+ ::: impl.body
335302 }
336303 else impl.body)
337304 }
0 commit comments