aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2017-01-28 17:02:47 +0100
committerGitHub <noreply@github.com>2017-01-28 17:02:47 +0100
commitd5201d3da5b6edb1abc61b51f125c0a3fd56000c (patch)
tree69c9ee904b8ae92049141b0f04cb95d2d51fc3b6 /compiler
parent494aee2feef50fadaf9f851eae4128e8dad81f8a (diff)
parent945001d439d062f42515f0bb4b8b86136b09fe4c (diff)
downloaddotty-d5201d3da5b6edb1abc61b51f125c0a3fd56000c.tar.gz
dotty-d5201d3da5b6edb1abc61b51f125c0a3fd56000c.tar.bz2
dotty-d5201d3da5b6edb1abc61b51f125c0a3fd56000c.zip
Merge pull request #1909 from dotty-staging/fix-1687
Fix #1687: postpone computations in tailrec until they are needed.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TailRec.scala73
1 files changed, 39 insertions, 34 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala
index dc4454439..3e7a7ed89 100644
--- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala
@@ -216,18 +216,13 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
val (prefix, call, arguments, typeArguments, symbol) = receiverArgumentsAndSymbol(tree)
val hasConformingTargs = (typeArguments zip methTparams).forall{x => x._1.tpe <:< x._2.tpe}
- val recv = noTailTransform(prefix)
val targs = typeArguments.map(noTailTransform)
val argumentss = arguments.map(noTailTransforms)
- 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 || recv.tpe.widen =:= thisType
-
val isRecursiveCall = (method eq sym)
+ val recvWiden = prefix.tpe.widenDealias
+
def continue = {
val method = noTailTransform(call)
@@ -244,40 +239,50 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
continue
}
- def rewriteTailCall(recv: Tree): Tree = {
- c.debuglog("Rewriting tail recursive call: " + tree.pos)
- rewrote = true
- val receiver = noTailTransform(recv)
-
- 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 = if (callTargs.nonEmpty) TypeApply(Ident(label.termRef), callTargs) else Ident(label.termRef)
- val thisPassed =
- if (this.method.owner.isClass)
- method.appliedTo(receiver.ensureConforms(method.tpe.widen.firstParamTypes.head))
- else method
-
- val res =
- if (thisPassed.tpe.widen.isParameterless) thisPassed
- else argumentss.foldLeft(thisPassed) {
- (met, ar) => Apply(met, ar) // Dotty deviation no auto-detupling yet.
- }
- res
- }
+
if (isRecursiveCall) {
if (ctx.tailPos) {
+ val receiverIsSame = enclosingClass.typeRef.widenDealias =:= recvWiden
+ val receiverIsThis = prefix.tpe =:= thisType || prefix.tpe.widen =:= thisType
+
+ def rewriteTailCall(recv: Tree): Tree = {
+ c.debuglog("Rewriting tail recursive call: " + tree.pos)
+ rewrote = true
+ val receiver = noTailTransform(recv)
+
+ 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 = if (callTargs.nonEmpty) TypeApply(Ident(label.termRef), callTargs) else Ident(label.termRef)
+ val thisPassed =
+ if (this.method.owner.isClass)
+ method.appliedTo(receiver.ensureConforms(method.tpe.widen.firstParamTypes.head))
+ else method
+
+ val res =
+ if (thisPassed.tpe.widen.isParameterless) thisPassed
+ else argumentss.foldLeft(thisPassed) {
+ (met, ar) => Apply(met, ar) // Dotty deviation no auto-detupling yet.
+ }
+ res
+ }
+
if (!hasConformingTargs) fail("it changes type arguments on a polymorphic recursive call")
- else if (recv eq EmptyTree) rewriteTailCall(This(enclosingClass.asClass))
- else if (receiverIsSame || receiverIsThis) rewriteTailCall(recv)
- else fail("it changes type of 'this' on a polymorphic recursive call")
+ else {
+ val recv = noTailTransform(prefix)
+ if (recv eq EmptyTree) rewriteTailCall(This(enclosingClass.asClass))
+ else if (receiverIsSame || receiverIsThis) rewriteTailCall(recv)
+ else fail("it changes type of 'this' on a polymorphic recursive call")
+ }
}
else fail(defaultReason)
} else {
+ val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recvWiden
+
if (receiverIsSuper) fail("it contains a recursive call targeting a supertype")
else continue
}