aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform/FullParameterization.scala
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2016-02-15 15:37:55 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2016-03-31 14:49:23 +0200
commit07833e93f62cbe6d866300475288e8a763a36198 (patch)
treeca68403be647950d5a69eda1ba7fef5938f66656 /src/dotty/tools/dotc/transform/FullParameterization.scala
parent80b12473d7e7c5551ed7b13a835f239445662813 (diff)
downloaddotty-07833e93f62cbe6d866300475288e8a763a36198.tar.gz
dotty-07833e93f62cbe6d866300475288e8a763a36198.tar.bz2
dotty-07833e93f62cbe6d866300475288e8a763a36198.zip
FullParametrization: allow to have $this of ThisType.
TailRec methods remain members of enclosing class, it means that they can refer to methods that require this.type. It means that tailrec, unlike value classes is not allowed to widen type of $this to it's full self type. Fixes #1089
Diffstat (limited to 'src/dotty/tools/dotc/transform/FullParameterization.scala')
-rw-r--r--src/dotty/tools/dotc/transform/FullParameterization.scala34
1 files changed, 27 insertions, 7 deletions
diff --git a/src/dotty/tools/dotc/transform/FullParameterization.scala b/src/dotty/tools/dotc/transform/FullParameterization.scala
index e9057e885..cc8aeb9c4 100644
--- a/src/dotty/tools/dotc/transform/FullParameterization.scala
+++ b/src/dotty/tools/dotc/transform/FullParameterization.scala
@@ -12,6 +12,8 @@ import NameOps._
import ast._
import ast.Trees._
+import scala.reflect.internal.util.Collections
+
/** Provides methods to produce fully parameterized versions of instance methods,
* where the `this` of the enclosing class is abstracted out in an extra leading
* `$this` parameter and type parameters of the class become additional type
@@ -86,9 +88,12 @@ trait FullParameterization {
* }
*
* If a self type is present, $this has this self type as its type.
+ *
* @param abstractOverClass if true, include the type parameters of the class in the method's list of type parameters.
+ * @param liftThisType if true, require created $this to be $this: (Foo[A] & Foo,this).
+ * This is needed of created member stays inside scope of Foo(as in tailrec)
*/
- def fullyParameterizedType(info: Type, clazz: ClassSymbol, abstractOverClass: Boolean = true)(implicit ctx: Context): Type = {
+ def fullyParameterizedType(info: Type, clazz: ClassSymbol, abstractOverClass: Boolean = true, liftThisType: Boolean = false)(implicit ctx: Context): Type = {
val (mtparamCount, origResult) = info match {
case info @ PolyType(mtnames) => (mtnames.length, info.resultType)
case info: ExprType => (0, info.resultType)
@@ -100,7 +105,8 @@ trait FullParameterization {
/** The method result type */
def resultType(mapClassParams: Type => Type) = {
val thisParamType = mapClassParams(clazz.classInfo.selfType)
- MethodType(nme.SELF :: Nil, thisParamType :: Nil)(mt =>
+ val firstArgType = if (liftThisType) thisParamType & clazz.thisType else thisParamType
+ MethodType(nme.SELF :: Nil, firstArgType :: Nil)(mt =>
mapClassParams(origResult).substThisUnlessStatic(clazz, MethodParam(mt, 0)))
}
@@ -217,12 +223,26 @@ trait FullParameterization {
* - the `this` of the enclosing class,
* - the value parameters of the original method `originalDef`.
*/
- def forwarder(derived: TermSymbol, originalDef: DefDef, abstractOverClass: Boolean = true)(implicit ctx: Context): Tree =
+ def forwarder(derived: TermSymbol, originalDef: DefDef, abstractOverClass: Boolean = true, liftThisType: Boolean = false)(implicit ctx: Context): Tree = {
+ val fun =
ref(derived.termRef)
- .appliedToTypes(allInstanceTypeParams(originalDef, abstractOverClass).map(_.typeRef))
- .appliedTo(This(originalDef.symbol.enclosingClass.asClass))
- .appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol)))
- .withPos(originalDef.rhs.pos)
+ .appliedToTypes(allInstanceTypeParams(originalDef, abstractOverClass).map(_.typeRef))
+ .appliedTo(This(originalDef.symbol.enclosingClass.asClass))
+
+ (if (!liftThisType)
+ fun.appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol)))
+ else {
+ // this type could have changed on forwarding. Need to insert a cast.
+ val args = Collections.map2(originalDef.vparamss, fun.tpe.paramTypess)((vparams, paramTypes) =>
+ Collections.map2(vparams, paramTypes)((vparam, paramType) => {
+ assert(vparam.tpe <:< paramType.widen) // type should still conform to widened type
+ ref(vparam.symbol).ensureConforms(paramType)
+ })
+ )
+ fun.appliedToArgss(args)
+
+ }).withPos(originalDef.rhs.pos)
+ }
}
object FullParameterization {