@@ -60,11 +60,12 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
6060
6161 /** If argument is complex, hoist it out into its own method and refer to the
6262 * method instead.
63- * @param arg The argument that might be hoisted
64- * @param cdef The definition of the constructor from which the call is made
63+ * @param arg The argument that might be hoisted
64+ * @param cdef The definition of the constructor from which the call is made
65+ * @param lifted Argument definitions that were lifted out in a call prefix
6566 * @return The argument after possible hoisting
6667 */
67- private def hoistSuperArg (arg : Tree , cdef : DefDef ): Tree = {
68+ private def hoistSuperArg (arg : Tree , cdef : DefDef , lifted : List [ Symbol ] ): Tree = {
6869 val constr = cdef.symbol
6970 lazy val origParams = // The parameters that can be accessed in the supercall
7071 if (constr == cls.primaryConstructor)
@@ -92,36 +93,39 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
9293 val argTypeWrtConstr = argType.widenTermRefExpr.subst(origParams, allParamRefs(constr.info))
9394 // argType with references to paramRefs of the primary constructor instead of
9495 // local parameter accessors
96+ val abstractedArgType =
97+ if lifted.isEmpty then argTypeWrtConstr
98+ else MethodType .fromSymbols(lifted, argTypeWrtConstr)
9599 newSymbol(
96100 owner = methOwner,
97101 name = SuperArgName .fresh(cls.name.toTermName),
98102 flags = Synthetic | Private | Method | staticFlag,
99- info = replaceResult(constr.info, argTypeWrtConstr ),
103+ info = replaceResult(constr.info, abstractedArgType ),
100104 coord = constr.coord
101105 ).enteredAfter(thisPhase)
102106 }
103107
104108 /** Type of a reference implies that it needs to be hoisted */
105109 def refNeedsHoist (tp : Type ): Boolean = tp match {
106- case tp : ThisType => ! tp.cls.isStaticOwner && tp.cls != cls
110+ case tp : ThisType => ! tp.cls.isStaticOwner && ! cls.isContainedIn( tp.cls)
107111 case tp : TermRef => refNeedsHoist(tp.prefix)
108112 case _ => false
109113 }
110114
111115 /** Super call argument is complex, needs to be hoisted */
112- def needsHoist (tree : Tree ) = tree match {
116+ def needsHoist (tree : Tree ) = tree match
113117 case _ : DefDef => true
114118 case _ : Template => true
115119 case _ : New => ! tree.tpe.typeSymbol.isStatic
116120 case _ : RefTree | _ : This => refNeedsHoist(tree.tpe)
117121 case _ => false
118- }
119122
120123 /** Only rewire types that are owned by the current Hoister and is an param or accessor */
121124 def needsRewire (tp : Type ) = tp match {
122125 case ntp : NamedType =>
123126 val owner = ntp.symbol.maybeOwner
124127 (owner == cls || owner == constr) && ntp.symbol.isParamOrAccessor
128+ || lifted.contains(ntp.symbol)
125129 case _ => false
126130 }
127131
@@ -134,7 +138,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
134138 if pref.isType then pref.tpe.typeSymbol else pref.symbol)
135139 val tmap = new TreeTypeMap (
136140 typeMap = new TypeMap {
137- lazy val origToParam = origParams.zip(paramSyms).toMap
141+ lazy val origToParam = ( origParams ::: lifted) .zip(paramSyms).toMap
138142 def apply (tp : Type ) = tp match {
139143 case tp : NamedType if needsRewire(tp) =>
140144 origToParam.get(tp.symbol) match {
@@ -164,35 +168,52 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
164168 Nil
165169 }
166170 val (typeParams, termParams) = origParams.span(_.isType)
167- val res = ref(superMeth)
171+ var res = ref(superMeth)
168172 .appliedToTypes(typeParams.map(_.typeRef))
169173 .appliedToArgss(termParamRefs(constr.info, termParams))
174+ if lifted.nonEmpty then
175+ res = res.appliedToArgs(lifted.map(ref))
170176 report.log(i " hoist $arg, cls = $cls = $res" )
171177 res
172178 case _ => arg
173179 }
174180 }
175181
176182 /** Hoist complex arguments in super call out of the class. */
177- def hoistSuperArgsFromCall (superCall : Tree , cdef : DefDef ): Tree = superCall match {
183+ def hoistSuperArgsFromCall (superCall : Tree , cdef : DefDef , lifted : mutable.ListBuffer [Symbol ]): Tree = superCall match
184+ case Block (defs, expr) =>
185+ cpy.Block (superCall)(
186+ stats = defs.mapconserve {
187+ case vdef : ValDef =>
188+ try cpy.ValDef (vdef)(rhs = hoistSuperArg(vdef.rhs, cdef, lifted.toList))
189+ finally lifted += vdef.symbol
190+ case ddef : DefDef =>
191+ try cpy.DefDef (ddef)(rhs = hoistSuperArg(ddef.rhs, cdef, lifted.toList))
192+ finally lifted += ddef.symbol
193+ case stat =>
194+ stat
195+ },
196+ expr = hoistSuperArgsFromCall(expr, cdef, lifted))
178197 case Apply (fn, args) =>
179- cpy.Apply (superCall)(hoistSuperArgsFromCall(fn, cdef), args.mapconserve(hoistSuperArg(_, cdef)))
198+ cpy.Apply (superCall)(
199+ hoistSuperArgsFromCall(fn, cdef, lifted),
200+ args.mapconserve(hoistSuperArg(_, cdef, lifted.toList)))
180201 case _ =>
181202 superCall
182- }
183203
184204 /** Hoist complex arguments in this-constructor call of secondary constructor out of the class. */
185205 def hoistSuperArgsFromConstr (stat : Tree ): Tree = stat match {
186- case stat : DefDef if stat.symbol.isClassConstructor =>
187- cpy.DefDef (stat)(rhs =
188- stat.rhs match {
189- case Block (superCall :: stats, expr) =>
190- val superCall1 = hoistSuperArgsFromCall(superCall, stat)
191- if (superCall1 eq superCall) stat.rhs
192- else cpy.Block (stat.rhs)(superCall1 :: stats, expr)
206+ case constr : DefDef if constr.symbol.isClassConstructor =>
207+ val lifted = new mutable.ListBuffer [Symbol ]
208+ cpy.DefDef (constr)(rhs =
209+ constr.rhs match
210+ case Block (stats @ (superCall :: stats1), expr : Literal ) =>
211+ cpy.Block (constr.rhs)(
212+ stats.derivedCons(hoistSuperArgsFromCall(superCall, constr, lifted), stats1),
213+ expr)
193214 case _ =>
194- hoistSuperArgsFromCall(stat .rhs, stat )
195- } )
215+ hoistSuperArgsFromCall(constr .rhs, constr, lifted )
216+ )
196217 case _ =>
197218 stat
198219 }
@@ -202,7 +223,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
202223 tdef.rhs match {
203224 case impl @ Template (cdef, superCall :: others, _, _) =>
204225 val hoist = new Hoister (tdef.symbol)
205- val hoistedSuperCall = hoist.hoistSuperArgsFromCall(superCall, cdef)
226+ val hoistedSuperCall = hoist.hoistSuperArgsFromCall(superCall, cdef, new mutable. ListBuffer )
206227 val hoistedBody = impl.body.mapconserve(hoist.hoistSuperArgsFromConstr)
207228 if (hoist.superArgDefs.isEmpty) tdef
208229 else {
0 commit comments