aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TailRec.scala73
-rw-r--r--tests/pos/i1687.scala10
-rw-r--r--tests/pos/i1687b.scala19
3 files changed, 68 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
}
diff --git a/tests/pos/i1687.scala b/tests/pos/i1687.scala
new file mode 100644
index 000000000..d91c851e6
--- /dev/null
+++ b/tests/pos/i1687.scala
@@ -0,0 +1,10 @@
+object O {
+ def f: String = {
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1
+ }
+}
diff --git a/tests/pos/i1687b.scala b/tests/pos/i1687b.scala
new file mode 100644
index 000000000..46bb6649c
--- /dev/null
+++ b/tests/pos/i1687b.scala
@@ -0,0 +1,19 @@
+object O {
+ def f: String = {
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1 +
+ "1" + 1 + "1" + 1
+ }
+}