diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/TailCalls.scala | 14 | ||||
-rw-r--r-- | test/files/run/t6900.scala | 36 |
2 files changed, 48 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index a767850cba..938499261e 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -220,7 +220,10 @@ abstract class TailCalls extends Transform { debuglog("Rewriting tail recursive call: " + fun.pos.lineContent.trim) accessed += ctx.label - typedPos(fun.pos)(Apply(Ident(ctx.label), noTailTransform(recv) :: transformArgs)) + typedPos(fun.pos) { + val args = mapWithIndex(transformArgs)((arg, i) => mkAttributedCastHack(arg, ctx.label.info.params(i + 1).tpe)) + Apply(Ident(ctx.label), noTailTransform(recv) :: args) + } } if (!ctx.isEligible) fail("it is neither private nor final so can be overridden") @@ -280,7 +283,7 @@ abstract class TailCalls extends Transform { typedPos(tree.pos)(Block( List(ValDef(newThis, This(currentClass))), - LabelDef(newCtx.label, newThis :: vpSyms, newRHS) + LabelDef(newCtx.label, newThis :: vpSyms, mkAttributedCastHack(newRHS, newCtx.label.tpe.resultType)) )) } else { @@ -377,6 +380,13 @@ abstract class TailCalls extends Transform { super.transform(tree) } } + + // Workaround for SI-6900. Uncurry installs an InfoTransformer and a tree Transformer. + // These leave us with conflicting view on method signatures; the parameter symbols in + // the MethodType can be clones of the ones originally found on the parameter ValDef, and + // consequently appearing in the typechecked RHS of the method. + private def mkAttributedCastHack(tree: Tree, tpe: Type) = + gen.mkAttributedCast(tree, tpe) } // collect the LabelDefs (generated by the pattern matcher) in a DefDef that are in tail position diff --git a/test/files/run/t6900.scala b/test/files/run/t6900.scala new file mode 100644 index 0000000000..a29d388129 --- /dev/null +++ b/test/files/run/t6900.scala @@ -0,0 +1,36 @@ +import annotation.tailrec + +trait Universe { + type T <: AnyRef +} + +final class Bug { + var i = 1 + def stop() = { i -= 1; i < 0 } + // the alias bypasses the fast path in erasures InfoTransformer + // predicated on `TypeMap.noChangeToSymbols` + type Alias = Any + + @tailrec + // So we get two symbols for `universe`, the original on the ValDef + // and a clone in the MethodType of `f`. + def f(universe: Universe, l: Alias): universe.T = { + if (stop()) null.asInstanceOf[universe.T] else f(universe, null) + } + + @tailrec + def g(universe: Universe)(l: Alias): universe.T = { + if (stop()) null.asInstanceOf[universe.T] else g(universe)(l) + } + + @tailrec + def h(universe: Universe)(l: List[universe.T]): List[universe.T] = { + if (stop()) Nil else h(universe)(l) + } +} + +object Test extends App { + assert(new Bug().f(null, null) == null) + assert(new Bug().g(null)(null) == null) + assert(new Bug().h(null)(null) == Nil) +}
\ No newline at end of file |