From e5fcf57b1e62e420c611ed58d475d081d95f9048 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 15 Nov 2015 11:48:37 +0100 Subject: Fix problems arising when hierarchies of classes are under completion Fix problems arising when hierarchies of classes are under completion at the same time. In this case it can happen that we see a subclass (e.g. Arrays.scala) which depends on a superclass (e.g. GenTraversableLike.scala) that itself does not have its parents defined yet. Previously, several things went wrong here - One of the base classes would be marked as frozen, even though it dod not have all members entered yet. This led to an error in finger printing. - The baseclasses and super class bits of the subclass would be computed before the parents of the middle class were known. The baseclasses would then be chached, leading to false results for isDerivedFrom. We need to refine the logic for computing base classes, super class bits, and fingerprints to account for that issue. --- src/dotty/tools/dotc/core/SymDenotations.scala | 48 +++++++++++++++++--------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'src/dotty/tools/dotc/core/SymDenotations.scala') diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 2f2703397..00ca99da5 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1213,8 +1213,17 @@ object SymDenotations { * ClassDenotations compiled from source are first completed, then fully completed. * @see Namer#ClassCompleter */ - private def isFullyCompleted(implicit ctx: Context): Boolean = - isCompleted && classParents.nonEmpty + private def isFullyCompleted(implicit ctx: Context): Boolean = { + def isFullyCompletedRef(tp: TypeRef) = tp.denot match { + case d: ClassDenotation => d.isFullyCompleted + case _ => false + } + def isLocallyFullyCompleted = + if (classParents.isEmpty) is(Package) || symbol.eq(defn.AnyClass) + else classParents.forall(isFullyCompletedRef) + flagsUNSAFE.is(FullyCompleted) || + isCompleted && isLocallyFullyCompleted && { setFlag(FullyCompleted); true } + } // ------ syncing inheritance-related info ----------------------------- @@ -1300,7 +1309,7 @@ object SymDenotations { baseTypeRefValid = ctx.runId } - private def computeBases(implicit ctx: Context): Unit = { + private def computeBases(implicit ctx: Context): (List[ClassSymbol], BitSet) = { if (myBaseClasses eq Nil) throw CyclicReference(this) myBaseClasses = Nil val seen = new mutable.BitSet @@ -1324,8 +1333,14 @@ object SymDenotations { case nil => to } - myBaseClasses = classSymbol :: addParentBaseClasses(classParents, Nil) - mySuperClassBits = seen.toImmutable + val bcs = classSymbol :: addParentBaseClasses(classParents, Nil) + val scbits = seen.toImmutable + if (isFullyCompleted) { + myBaseClasses = bcs + mySuperClassBits = scbits + } + else myBaseClasses = null + (bcs, scbits) } /** A bitset that contains the superId's of all base classes */ @@ -1333,8 +1348,7 @@ object SymDenotations { if (classParents.isEmpty) BitSet() // can happen when called too early in Namers else { checkBasesUpToDate() - if (mySuperClassBits == null) computeBases - mySuperClassBits + if (mySuperClassBits != null) mySuperClassBits else computeBases._2 } /** The base classes of this class in linearization order, @@ -1344,8 +1358,7 @@ object SymDenotations { if (classParents.isEmpty) classSymbol :: Nil // can happen when called too early in Namers else { checkBasesUpToDate() - if (myBaseClasses == null) computeBases - myBaseClasses + if (myBaseClasses != null) myBaseClasses else computeBases._1 } final override def derivesFrom(base: Symbol)(implicit ctx: Context): Boolean = @@ -1378,9 +1391,9 @@ object SymDenotations { while (ps.nonEmpty) { val parent = ps.head.typeSymbol parent.denot match { - case classd: ClassDenotation => - fp.include(classd.memberFingerPrint) - parent.denot.setFlag(Frozen) + case parentDenot: ClassDenotation => + fp.include(parentDenot.memberFingerPrint) + if (parentDenot.isFullyCompleted) parentDenot.setFlag(Frozen) case _ => } ps = ps.tail @@ -1393,10 +1406,13 @@ object SymDenotations { * not be used for package classes because cache never * gets invalidated. */ - def memberFingerPrint(implicit ctx: Context): FingerPrint = { - if (myMemberFingerPrint == FingerPrint.unknown) myMemberFingerPrint = computeMemberFingerPrint - myMemberFingerPrint - } + def memberFingerPrint(implicit ctx: Context): FingerPrint = + if (myMemberFingerPrint != FingerPrint.unknown) myMemberFingerPrint + else { + val fp = computeMemberFingerPrint + if (isFullyCompleted) myMemberFingerPrint = fp + fp + } private[this] var myMemberCache: LRUCache[Name, PreDenotation] = null private[this] var myMemberCachePeriod: Period = Nowhere -- cgit v1.2.3