Skip to content

Commit f3bf225

Browse files
authored
Merge pull request #1848 from dotty-staging/fix-#1795
Fix #1795: Avoid infinite recursion between member and asSeenFrom
2 parents 098c50a + d1b7f2c commit f3bf225

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ object Config {
133133
*/
134134
final val LogPendingFindMemberThreshold = 10
135135

136-
/** Maximal number of outstanding recursive calls to findMember */
136+
/** Maximal number of outstanding recursive calls to findMember before backing out
137+
* when findMemberLimit is set.
138+
*/
137139
final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 4
138140
}

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import NameOps._
1010
import Decorators._
1111
import StdNames._
1212
import Annotations._
13-
import util.SimpleMap
13+
import config.Config
14+
import util.{SimpleMap, Property}
1415
import collection.mutable
1516
import ast.tpd._
1617

@@ -67,7 +68,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
6768
if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists) {
6869
if (theMap != null && theMap.currentVariance <= 0 && !isLegalPrefix(pre)) {
6970
ctx.base.unsafeNonvariant = ctx.runId
70-
AnnotatedType(pre, Annotation(defn.UnsafeNonvariantAnnot, Nil))
71+
pre match {
72+
case AnnotatedType(_, ann) if ann.symbol == defn.UnsafeNonvariantAnnot => pre
73+
case _ => AnnotatedType(pre, Annotation(defn.UnsafeNonvariantAnnot, Nil))
74+
}
7175
}
7276
else pre
7377
}
@@ -85,13 +89,15 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
8589
if (sym.isStatic) tp
8690
else {
8791
val pre1 = asSeenFrom(tp.prefix, pre, cls, theMap)
88-
if (pre1.isUnsafeNonvariant)
89-
pre1.member(tp.name).info match {
92+
if (pre1.isUnsafeNonvariant) {
93+
val safeCtx = ctx.withProperty(TypeOps.findMemberLimit, Some(()))
94+
pre1.member(tp.name)(safeCtx).info match {
9095
case TypeAlias(alias) =>
9196
// try to follow aliases of this will avoid skolemization.
9297
return alias
9398
case _ =>
9499
}
100+
}
95101
tp.derivedSelect(pre1)
96102
}
97103
case tp: ThisType =>
@@ -554,4 +560,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
554560

555561
object TypeOps {
556562
@sharable var track = false // !!!DEBUG
563+
564+
/** When a property with this key is set in a context, it limit the number
565+
* of recursive member searches. If the limit is reached, findMember returns
566+
* NoDenotation.
567+
*/
568+
val findMemberLimit = new Property.Key[Unit]
557569
}

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,12 @@ object Types {
573573

574574
{ val recCount = ctx.findMemberCount + 1
575575
ctx.findMemberCount = recCount
576-
if (recCount >= Config.LogPendingFindMemberThreshold)
576+
if (recCount >= Config.LogPendingFindMemberThreshold) {
577577
ctx.pendingMemberSearches = name :: ctx.pendingMemberSearches
578+
if (ctx.property(TypeOps.findMemberLimit).isDefined &&
579+
ctx.findMemberCount > Config.PendingFindMemberLimit)
580+
return NoDenotation
581+
}
578582
}
579583

580584
//assert(ctx.findMemberCount < 20)

tests/pos/i1795.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
sealed trait T1 {type M1}
2+
3+
case object o1 extends T1
4+
5+
sealed trait T2 {type M2}
6+
7+
case object o2 extends T2
8+
9+
class TestX {
10+
type TestT1 <: T1 {type M1 = TestT2}
11+
type TestT2 <: T2 {type M2 = TestT1}
12+
//val x: TestT1 = o1
13+
}

0 commit comments

Comments
 (0)