Skip to content

Commit 0265439

Browse files
committed
Take lifted arguments into accountfor supercall argumemts
Since we never housted arguments if the supercall had lifted parameters, we did not exercise that case before. Some fixes were necessary to make it work.
1 parent 3b14fca commit 0265439

File tree

2 files changed

+54
-28
lines changed

2 files changed

+54
-28
lines changed

compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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,11 +93,14 @@ 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
}
@@ -122,6 +126,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
122126
case ntp: NamedType =>
123127
val owner = ntp.symbol.maybeOwner
124128
(owner == cls || owner == constr) && ntp.symbol.isParamOrAccessor
129+
|| lifted.contains(ntp.symbol)
125130
case _ => false
126131
}
127132

@@ -134,7 +139,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
134139
if pref.isType then pref.tpe.typeSymbol else pref.symbol)
135140
val tmap = new TreeTypeMap(
136141
typeMap = new TypeMap {
137-
lazy val origToParam = origParams.zip(paramSyms).toMap
142+
lazy val origToParam = (origParams ::: lifted).zip(paramSyms).toMap
138143
def apply(tp: Type) = tp match {
139144
case tp: NamedType if needsRewire(tp) =>
140145
origToParam.get(tp.symbol) match {
@@ -164,45 +169,52 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
164169
Nil
165170
}
166171
val (typeParams, termParams) = origParams.span(_.isType)
167-
val res = ref(superMeth)
172+
var res = ref(superMeth)
168173
.appliedToTypes(typeParams.map(_.typeRef))
169174
.appliedToArgss(termParamRefs(constr.info, termParams))
175+
if lifted.nonEmpty then
176+
res = res.appliedToArgs(lifted.map(ref))
170177
report.log(i"hoist $arg, cls = $cls = $res")
171178
res
172179
case _ => arg
173180
}
174181
}
175182

176-
/** Hoist super arg from a lifted parameter that gets evaluated before the call */
177-
def hoistSuperArgFromDef(paramDef: Tree, cdef: DefDef): Tree = paramDef match
178-
case vdef: ValDef =>
179-
cpy.ValDef(vdef)(rhs = hoistSuperArg(vdef.rhs, cdef))
180-
case ddef: DefDef =>
181-
cpy.DefDef(ddef)(rhs = hoistSuperArg(ddef.rhs, cdef))
182-
case _ =>
183-
paramDef
184-
185183
/** Hoist complex arguments in super call out of the class. */
186-
def hoistSuperArgsFromCall(superCall: Tree, cdef: DefDef): Tree = superCall match
184+
def hoistSuperArgsFromCall(superCall: Tree, cdef: DefDef, lifted: mutable.ListBuffer[Symbol]): Tree = superCall match
187185
case Block(defs, expr) =>
188-
cpy.Block(superCall)(defs.mapconserve(hoistSuperArgFromDef(_, cdef)), hoistSuperArgsFromCall(expr, cdef))
186+
cpy.Block(superCall)(
187+
stats = defs.mapconserve {
188+
case vdef: ValDef =>
189+
try cpy.ValDef(vdef)(rhs = hoistSuperArg(vdef.rhs, cdef, lifted.toList))
190+
finally lifted += vdef.symbol
191+
case ddef: DefDef =>
192+
try cpy.DefDef(ddef)(rhs = hoistSuperArg(ddef.rhs, cdef, lifted.toList))
193+
finally lifted += ddef.symbol
194+
case stat =>
195+
stat
196+
},
197+
expr = hoistSuperArgsFromCall(expr, cdef, lifted))
189198
case Apply(fn, args) =>
190-
cpy.Apply(superCall)(hoistSuperArgsFromCall(fn, cdef), args.mapconserve(hoistSuperArg(_, cdef)))
199+
cpy.Apply(superCall)(
200+
hoistSuperArgsFromCall(fn, cdef, lifted),
201+
args.mapconserve(hoistSuperArg(_, cdef, lifted.toList)))
191202
case _ =>
192203
superCall
193204

194205
/** Hoist complex arguments in this-constructor call of secondary constructor out of the class. */
195206
def hoistSuperArgsFromConstr(stat: Tree): Tree = stat match {
196-
case stat: DefDef if stat.symbol.isClassConstructor =>
197-
cpy.DefDef(stat)(rhs =
198-
stat.rhs match {
199-
case Block(superCall :: stats, expr) =>
200-
val superCall1 = hoistSuperArgsFromCall(superCall, stat)
201-
if (superCall1 eq superCall) stat.rhs
202-
else cpy.Block(stat.rhs)(superCall1 :: stats, expr)
207+
case constr: DefDef if constr.symbol.isClassConstructor =>
208+
val lifted = new mutable.ListBuffer[Symbol]
209+
cpy.DefDef(constr)(rhs =
210+
constr.rhs match
211+
case Block(stats @ (superCall :: stats1), expr: Literal) =>
212+
cpy.Block(constr.rhs)(
213+
stats.derivedCons(hoistSuperArgsFromCall(superCall, constr, lifted), stats1),
214+
expr)
203215
case _ =>
204-
hoistSuperArgsFromCall(stat.rhs, stat)
205-
})
216+
hoistSuperArgsFromCall(constr.rhs, constr, lifted)
217+
)
206218
case _ =>
207219
stat
208220
}
@@ -212,7 +224,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
212224
tdef.rhs match {
213225
case impl @ Template(cdef, superCall :: others, _, _) =>
214226
val hoist = new Hoister(tdef.symbol)
215-
val hoistedSuperCall = hoist.hoistSuperArgsFromCall(superCall, cdef)
227+
val hoistedSuperCall = hoist.hoistSuperArgsFromCall(superCall, cdef, new mutable.ListBuffer)
216228
val hoistedBody = impl.body.mapconserve(hoist.hoistSuperArgsFromConstr)
217229
if (hoist.superArgDefs.isEmpty) tdef
218230
else {

tests/run/i14164.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
object Test:
23
class Base(a: String = "x", param: String)
34

@@ -11,3 +12,16 @@ object Test:
1112

1213
def main(args: Array[String]) = ()
1314

15+
end Test
16+
17+
class Test2:
18+
class Inner(withDefault: String = "inner")(
19+
dependentDefault: String = withDefault) extends Object {
20+
def this(x: Int) = this(x.toString)()
21+
}
22+
23+
class Test3:
24+
class Inner(withDefault: () => String = () => "inner")(
25+
dependentDefault: String = withDefault()) extends Object {
26+
def this(x: Int) = this(() => x.toString)()
27+
}

0 commit comments

Comments
 (0)