aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2015-01-26 14:20:18 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2015-02-03 15:10:10 +0100
commit12d4182cc9da27eca9d55a94d148f4a8dadbc11d (patch)
tree9d74e6ed566be48bd89916756b00f8a1b6284758 /src/dotty/tools/dotc/transform
parenta14af3e7bf82e793d0b687bf6e53b6bc61f1ec5a (diff)
downloaddotty-12d4182cc9da27eca9d55a94d148f4a8dadbc11d.tar.gz
dotty-12d4182cc9da27eca9d55a94d148f4a8dadbc11d.tar.bz2
dotty-12d4182cc9da27eca9d55a94d148f4a8dadbc11d.zip
Even more careful handling of tailcalls.
See i321 doc for description of problem and decision taken.
Diffstat (limited to 'src/dotty/tools/dotc/transform')
-rw-r--r--src/dotty/tools/dotc/transform/TailRec.scala42
1 files changed, 23 insertions, 19 deletions
diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala
index 15f4f9b4f..b747636c7 100644
--- a/src/dotty/tools/dotc/transform/TailRec.scala
+++ b/src/dotty/tools/dotc/transform/TailRec.scala
@@ -74,23 +74,25 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
final val labelPrefix = "tailLabel"
final val labelFlags = Flags.Synthetic | Flags.Label
- private def mkLabel(method: Symbol)(implicit c: Context): TermSymbol = {
+ private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit c: Context): TermSymbol = {
val name = c.freshName(labelPrefix)
- c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass = false))
+ c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass))
}
override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ val sym = tree.symbol
tree match {
case dd@DefDef(name, tparams, vparamss0, tpt, rhs0)
- if (dd.symbol.isEffectivelyFinal) && !((dd.symbol is Flags.Accessor) || (rhs0 eq EmptyTree) || (dd.symbol is Flags.Label)) =>
- val mandatory = dd.symbol.hasAnnotation(defn.TailrecAnnotationClass)
+ if (sym.isEffectivelyFinal) && !((sym is Flags.Accessor) || (rhs0 eq EmptyTree) || (sym is Flags.Label)) =>
+ val mandatory = sym.hasAnnotation(defn.TailrecAnnotationClass)
atGroupEnd { implicit ctx: Context =>
cpy.DefDef(dd)(rhs = {
- val origMeth = tree.symbol
- val label = mkLabel(dd.symbol)
+ val defIsTopLevel = sym.owner.isClass
+ val origMeth = sym
+ val label = mkLabel(sym, abstractOverClass = defIsTopLevel)
val owner = ctx.owner.enclosingClass.asClass
val thisTpe = owner.thisType.widen
@@ -101,7 +103,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
// and second one will actually apply,
// now this speculatively transforms tree and throws away result in many cases
val rhsSemiTransformed = {
- val transformer = new TailRecElimination(dd.symbol, owner, thisTpe, mandatory, label)
+ val transformer = new TailRecElimination(origMeth, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel)
val rhs = atGroupEnd(transformer.transform(rhs0)(_))
rewrote = transformer.rewrote
rhs
@@ -109,8 +111,8 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
if (rewrote) {
val dummyDefDef = cpy.DefDef(tree)(rhs = rhsSemiTransformed)
- val res = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = false)
- val call = forwarder(label, dd, abstractOverClass = false)
+ val res = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = defIsTopLevel)
+ val call = forwarder(label, dd, abstractOverClass = defIsTopLevel)
Block(List(res), call)
} else {
if (mandatory)
@@ -130,7 +132,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
}
- class TailRecElimination(method: Symbol, enclosingClass: Symbol, thisType: Type, isMandatory: Boolean, label: Symbol) extends tpd.TreeMap {
+ class TailRecElimination(method: Symbol, enclosingClass: Symbol, thisType: Type, isMandatory: Boolean, label: Symbol, abstractOverClass: Boolean) extends tpd.TreeMap {
import dotty.tools.dotc.ast.tpd._
@@ -179,9 +181,11 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
val targs = typeArguments.map(noTailTransform)
val argumentss = arguments.map(noTailTransforms)
- val receiverIsSame = enclosingClass.typeRef.widen =:= recv.tpe.widen
- val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recv.tpe.widen
- val receiverIsThis = recv.tpe.widen =:= thisType
+ val recvWiden = recv.tpe.widenDealias
+
+ val receiverIsSame = enclosingClass.typeRef.widenDealias =:= recvWiden
+ val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recvWiden
+ val receiverIsThis = recv.tpe =:= thisType
val isRecursiveCall = (method eq sym)
@@ -205,12 +209,12 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
rewrote = true
val reciever = noTailTransform(recv)
- /*
- handling changed type arguments in sound way is hard, see test `i321`
- val classTypeArgs = recv.tpe.baseTypeWithArgs(enclosingClass).argInfos
- val trz = classTypeArgs.map(x => ref(x.typeSymbol))
- */
- val callTargs: List[tpd.Tree] = targs
+ val callTargs: List[tpd.Tree] =
+ if(abstractOverClass) {
+ val classTypeArgs = recv.tpe.baseTypeWithArgs(enclosingClass).argInfos
+ targs ::: classTypeArgs.map(x => ref(x.typeSymbol))
+ } else targs
+
val method = Apply(if (callTargs.nonEmpty) TypeApply(Ident(label.termRef), callTargs) else Ident(label.termRef),
List(reciever))