Skip to content

Commit f8169b4

Browse files
committed
Merge pull request #944 from dotty-staging/fix-tailrec
Tailrec: fix compilation of IndexedSeqOptimized
2 parents f2b61ce + 9a9436a commit f8169b4

File tree

5 files changed

+60
-1
lines changed

5 files changed

+60
-1
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class Compiler {
5252
List(new PatternMatcher,
5353
new ExplicitOuter,
5454
new ExplicitSelf,
55+
new CrossCastAnd,
5556
new Splitter),
5657
List(new VCInlineMethods,
5758
new SeqLiterals,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package dotty.tools.dotc.transform
2+
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core.Contexts.Context
5+
import dotty.tools.dotc.core.Flags
6+
import dotty.tools.dotc.core.Types.{NoType, Type, AndType}
7+
import dotty.tools.dotc.transform.TreeTransforms._
8+
import tpd._
9+
10+
import scala.collection.mutable.ListBuffer
11+
12+
13+
/**
14+
* This transform makes sure that all private member selections from
15+
* AndTypes are performed from the first component of AndType.
16+
* This is needed for correctness of erasure. See `tests/run/PrivateAnd.scala`
17+
*/
18+
class CrossCastAnd extends MiniPhaseTransform { thisTransform =>
19+
20+
override def phaseName: String = "crossCast"
21+
22+
override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
23+
24+
lazy val qtype = tree.qualifier.tpe.widen
25+
val sym = tree.symbol
26+
if (sym.is(Flags.Private) && qtype.typeSymbol != sym.owner)
27+
cpy.Select(tree)(tree.qualifier.asInstance(AndType(qtype.baseTypeWithArgs(sym.owner), tree.qualifier.tpe)), tree.name)
28+
else tree
29+
}
30+
}

src/dotty/tools/dotc/transform/TailRec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
185185

186186
val receiverIsSame = enclosingClass.typeRef.widenDealias =:= recvWiden
187187
val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recvWiden
188-
val receiverIsThis = recv.tpe =:= thisType
188+
val receiverIsThis = recv.tpe =:= thisType || recv.tpe.widen =:= thisType
189189

190190
val isRecursiveCall = (method eq sym)
191191

tests/pos/ErasureAnd.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.annotation.tailrec
2+
trait A { self: B =>
3+
@tailrec
4+
private def foo(arg1: Int, arg2: Int): Int = {
5+
def bar = this.foo(arg1, arg2)
6+
foo(arg1, arg2)
7+
}
8+
def foo(arg: Int) = arg
9+
}
10+
11+
class B extends A{}

tests/run/PrivateAnd.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class A{
2+
private def foo = 1
3+
def callsFoo1(other: A & B): Int = other.foo
4+
def callsFoo2(other: B & A): Int = other.foo
5+
}
6+
7+
trait B {
8+
def foo(i: Int) = i
9+
}
10+
11+
object Test {
12+
def main(args: Array[String]): Unit = {
13+
val a = new A with B
14+
a.callsFoo1(a)
15+
a.callsFoo2(a)
16+
}
17+
}

0 commit comments

Comments
 (0)