@@ -60,11 +60,12 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
60
60
61
61
/** If argument is complex, hoist it out into its own method and refer to the
62
62
* 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
65
66
* @return The argument after possible hoisting
66
67
*/
67
- private def hoistSuperArg (arg : Tree , cdef : DefDef ): Tree = {
68
+ private def hoistSuperArg (arg : Tree , cdef : DefDef , lifted : List [ Symbol ] ): Tree = {
68
69
val constr = cdef.symbol
69
70
lazy val origParams = // The parameters that can be accessed in the supercall
70
71
if (constr == cls.primaryConstructor)
@@ -92,36 +93,39 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
92
93
val argTypeWrtConstr = argType.widenTermRefExpr.subst(origParams, allParamRefs(constr.info))
93
94
// argType with references to paramRefs of the primary constructor instead of
94
95
// local parameter accessors
96
+ val abstractedArgType =
97
+ if lifted.isEmpty then argTypeWrtConstr
98
+ else MethodType .fromSymbols(lifted, argTypeWrtConstr)
95
99
newSymbol(
96
100
owner = methOwner,
97
101
name = SuperArgName .fresh(cls.name.toTermName),
98
102
flags = Synthetic | Private | Method | staticFlag,
99
- info = replaceResult(constr.info, argTypeWrtConstr ),
103
+ info = replaceResult(constr.info, abstractedArgType ),
100
104
coord = constr.coord
101
105
).enteredAfter(thisPhase)
102
106
}
103
107
104
108
/** Type of a reference implies that it needs to be hoisted */
105
109
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)
107
111
case tp : TermRef => refNeedsHoist(tp.prefix)
108
112
case _ => false
109
113
}
110
114
111
115
/** Super call argument is complex, needs to be hoisted */
112
- def needsHoist (tree : Tree ) = tree match {
116
+ def needsHoist (tree : Tree ) = tree match
113
117
case _ : DefDef => true
114
118
case _ : Template => true
115
119
case _ : New => ! tree.tpe.typeSymbol.isStatic
116
120
case _ : RefTree | _ : This => refNeedsHoist(tree.tpe)
117
121
case _ => false
118
- }
119
122
120
123
/** Only rewire types that are owned by the current Hoister and is an param or accessor */
121
124
def needsRewire (tp : Type ) = tp match {
122
125
case ntp : NamedType =>
123
126
val owner = ntp.symbol.maybeOwner
124
127
(owner == cls || owner == constr) && ntp.symbol.isParamOrAccessor
128
+ || lifted.contains(ntp.symbol)
125
129
case _ => false
126
130
}
127
131
@@ -134,7 +138,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
134
138
if pref.isType then pref.tpe.typeSymbol else pref.symbol)
135
139
val tmap = new TreeTypeMap (
136
140
typeMap = new TypeMap {
137
- lazy val origToParam = origParams.zip(paramSyms).toMap
141
+ lazy val origToParam = ( origParams ::: lifted) .zip(paramSyms).toMap
138
142
def apply (tp : Type ) = tp match {
139
143
case tp : NamedType if needsRewire(tp) =>
140
144
origToParam.get(tp.symbol) match {
@@ -164,35 +168,52 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
164
168
Nil
165
169
}
166
170
val (typeParams, termParams) = origParams.span(_.isType)
167
- val res = ref(superMeth)
171
+ var res = ref(superMeth)
168
172
.appliedToTypes(typeParams.map(_.typeRef))
169
173
.appliedToArgss(termParamRefs(constr.info, termParams))
174
+ if lifted.nonEmpty then
175
+ res = res.appliedToArgs(lifted.map(ref))
170
176
report.log(i " hoist $arg, cls = $cls = $res" )
171
177
res
172
178
case _ => arg
173
179
}
174
180
}
175
181
176
182
/** 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))
178
197
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)))
180
201
case _ =>
181
202
superCall
182
- }
183
203
184
204
/** Hoist complex arguments in this-constructor call of secondary constructor out of the class. */
185
205
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)
193
214
case _ =>
194
- hoistSuperArgsFromCall(stat .rhs, stat )
195
- } )
215
+ hoistSuperArgsFromCall(constr .rhs, constr, lifted )
216
+ )
196
217
case _ =>
197
218
stat
198
219
}
@@ -202,7 +223,7 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase
202
223
tdef.rhs match {
203
224
case impl @ Template (cdef, superCall :: others, _, _) =>
204
225
val hoist = new Hoister (tdef.symbol)
205
- val hoistedSuperCall = hoist.hoistSuperArgsFromCall(superCall, cdef)
226
+ val hoistedSuperCall = hoist.hoistSuperArgsFromCall(superCall, cdef, new mutable. ListBuffer )
206
227
val hoistedBody = impl.body.mapconserve(hoist.hoistSuperArgsFromConstr)
207
228
if (hoist.superArgDefs.isEmpty) tdef
208
229
else {
0 commit comments