From e7b045a2fa9b1196465b388393ab23ce5979616e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 21 Dec 2016 18:43:27 +0100 Subject: Fix #1795: Avoid infinite recursion between member and asSeenFrom --- compiler/src/dotty/tools/dotc/config/Config.scala | 4 +++- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 20 ++++++++++++++++---- compiler/src/dotty/tools/dotc/core/Types.scala | 7 ++++++- 3 files changed, 25 insertions(+), 6 deletions(-) (limited to 'compiler/src/dotty/tools') diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 7744a5479..119af9483 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -133,6 +133,8 @@ object Config { */ final val LogPendingFindMemberThreshold = 10 - /** Maximal number of outstanding recursive calls to findMember */ + /** Maximal number of outstanding recursive calls to findMember before backing out + * when findMemberLimit is set. + */ final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 4 } diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index f134412a7..be8dc2713 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -10,7 +10,8 @@ import NameOps._ import Decorators._ import StdNames._ import Annotations._ -import util.SimpleMap +import config.Config +import util.{SimpleMap, Property} import collection.mutable import ast.tpd._ @@ -67,7 +68,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object. if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists) { if (theMap != null && theMap.currentVariance <= 0 && !isLegalPrefix(pre)) { ctx.base.unsafeNonvariant = ctx.runId - AnnotatedType(pre, Annotation(defn.UnsafeNonvariantAnnot, Nil)) + pre match { + case AnnotatedType(_, ann) if ann.symbol == defn.UnsafeNonvariantAnnot => pre + case _ => AnnotatedType(pre, Annotation(defn.UnsafeNonvariantAnnot, Nil)) + } } else pre } @@ -85,13 +89,15 @@ trait TypeOps { this: Context => // TODO: Make standalone object. if (sym.isStatic) tp else { val pre1 = asSeenFrom(tp.prefix, pre, cls, theMap) - if (pre1.isUnsafeNonvariant) - pre1.member(tp.name).info match { + if (pre1.isUnsafeNonvariant) { + val safeCtx = ctx.withProperty(TypeOps.findMemberLimit, Some(Config.PendingFindMemberLimit)) + pre1.member(tp.name)(safeCtx).info match { case TypeAlias(alias) => // try to follow aliases of this will avoid skolemization. return alias case _ => } + } tp.derivedSelect(pre1) } case tp: ThisType => @@ -554,4 +560,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object. object TypeOps { @sharable var track = false // !!!DEBUG + + /** When a property with this key is set in a context, it limit the number + * of recursive member searches. If the limit is reached, findMember returns + * NoDenotation. + */ + val findMemberLimit = new Property.Key[Int] } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 069b4f60d..dcc1019e4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -573,8 +573,13 @@ object Types { { val recCount = ctx.findMemberCount + 1 ctx.findMemberCount = recCount - if (recCount >= Config.LogPendingFindMemberThreshold) + if (recCount >= Config.LogPendingFindMemberThreshold) { ctx.pendingMemberSearches = name :: ctx.pendingMemberSearches + ctx.property(TypeOps.findMemberLimit) match { + case Some(limit) if ctx.findMemberCount > limit => return NoDenotation + case _ => + } + } } //assert(ctx.findMemberCount < 20) -- cgit v1.2.3