@@ -12,6 +12,8 @@ import NameOps._
12
12
import ast ._
13
13
import ast .Trees ._
14
14
15
+ import scala .reflect .internal .util .Collections
16
+
15
17
/** Provides methods to produce fully parameterized versions of instance methods,
16
18
* where the `this` of the enclosing class is abstracted out in an extra leading
17
19
* `$this` parameter and type parameters of the class become additional type
@@ -86,9 +88,12 @@ trait FullParameterization {
86
88
* }
87
89
*
88
90
* If a self type is present, $this has this self type as its type.
91
+ *
89
92
* @param abstractOverClass if true, include the type parameters of the class in the method's list of type parameters.
93
+ * @param liftThisType if true, require created $this to be $this: (Foo[A] & Foo,this).
94
+ * This is needed of created member stays inside scope of Foo(as in tailrec)
90
95
*/
91
- def fullyParameterizedType (info : Type , clazz : ClassSymbol , abstractOverClass : Boolean = true )(implicit ctx : Context ): Type = {
96
+ def fullyParameterizedType (info : Type , clazz : ClassSymbol , abstractOverClass : Boolean = true , liftThisType : Boolean = false )(implicit ctx : Context ): Type = {
92
97
val (mtparamCount, origResult) = info match {
93
98
case info @ PolyType (mtnames) => (mtnames.length, info.resultType)
94
99
case info : ExprType => (0 , info.resultType)
@@ -100,7 +105,8 @@ trait FullParameterization {
100
105
/** The method result type */
101
106
def resultType (mapClassParams : Type => Type ) = {
102
107
val thisParamType = mapClassParams(clazz.classInfo.selfType)
103
- MethodType (nme.SELF :: Nil , thisParamType :: Nil )(mt =>
108
+ val firstArgType = if (liftThisType) thisParamType & clazz.thisType else thisParamType
109
+ MethodType (nme.SELF :: Nil , firstArgType :: Nil )(mt =>
104
110
mapClassParams(origResult).substThisUnlessStatic(clazz, MethodParam (mt, 0 )))
105
111
}
106
112
@@ -217,12 +223,26 @@ trait FullParameterization {
217
223
* - the `this` of the enclosing class,
218
224
* - the value parameters of the original method `originalDef`.
219
225
*/
220
- def forwarder (derived : TermSymbol , originalDef : DefDef , abstractOverClass : Boolean = true )(implicit ctx : Context ): Tree =
226
+ def forwarder (derived : TermSymbol , originalDef : DefDef , abstractOverClass : Boolean = true , liftThisType : Boolean = false )(implicit ctx : Context ): Tree = {
227
+ val fun =
221
228
ref(derived.termRef)
222
- .appliedToTypes(allInstanceTypeParams(originalDef, abstractOverClass).map(_.typeRef))
223
- .appliedTo(This (originalDef.symbol.enclosingClass.asClass))
224
- .appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol)))
225
- .withPos(originalDef.rhs.pos)
229
+ .appliedToTypes(allInstanceTypeParams(originalDef, abstractOverClass).map(_.typeRef))
230
+ .appliedTo(This (originalDef.symbol.enclosingClass.asClass))
231
+
232
+ (if (! liftThisType)
233
+ fun.appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol)))
234
+ else {
235
+ // this type could have changed on forwarding. Need to insert a cast.
236
+ val args = Collections .map2(originalDef.vparamss, fun.tpe.paramTypess)((vparams, paramTypes) =>
237
+ Collections .map2(vparams, paramTypes)((vparam, paramType) => {
238
+ assert(vparam.tpe <:< paramType.widen) // type should still conform to widened type
239
+ ref(vparam.symbol).ensureConforms(paramType)
240
+ })
241
+ )
242
+ fun.appliedToArgss(args)
243
+
244
+ }).withPos(originalDef.rhs.pos)
245
+ }
226
246
}
227
247
228
248
object FullParameterization {
0 commit comments