Skip to content

Commit 38c50be

Browse files
committed
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.
1 parent 49e76d9 commit 38c50be

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ object Flags {
348348
/** A bridge method. Set by Erasure */
349349
final val Bridge = termFlag(34, "<bridge>")
350350

351+
/** All class attributes are fully defined */
352+
final val FullyCompleted = typeFlag(34, "<fully-completed>")
353+
351354
/** Symbol is a Java varargs bridge */ // (needed?)
352355
final val VBridge = termFlag(35, "<vbridge>") // TODO remove
353356

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,8 +1213,17 @@ object SymDenotations {
12131213
* ClassDenotations compiled from source are first completed, then fully completed.
12141214
* @see Namer#ClassCompleter
12151215
*/
1216-
private def isFullyCompleted(implicit ctx: Context): Boolean =
1217-
isCompleted && classParents.nonEmpty
1216+
private def isFullyCompleted(implicit ctx: Context): Boolean = {
1217+
def isFullyCompletedRef(tp: TypeRef) = tp.denot match {
1218+
case d: ClassDenotation => d.isFullyCompleted
1219+
case _ => false
1220+
}
1221+
def isLocallyFullyCompleted =
1222+
if (classParents.isEmpty) is(Package) || symbol.eq(defn.AnyClass)
1223+
else classParents.forall(isFullyCompletedRef)
1224+
flagsUNSAFE.is(FullyCompleted) ||
1225+
isCompleted && isLocallyFullyCompleted && { setFlag(FullyCompleted); true }
1226+
}
12181227

12191228
// ------ syncing inheritance-related info -----------------------------
12201229

@@ -1300,7 +1309,7 @@ object SymDenotations {
13001309
baseTypeRefValid = ctx.runId
13011310
}
13021311

1303-
private def computeBases(implicit ctx: Context): Unit = {
1312+
private def computeBases(implicit ctx: Context): (List[ClassSymbol], BitSet) = {
13041313
if (myBaseClasses eq Nil) throw CyclicReference(this)
13051314
myBaseClasses = Nil
13061315
val seen = new mutable.BitSet
@@ -1324,17 +1333,22 @@ object SymDenotations {
13241333
case nil =>
13251334
to
13261335
}
1327-
myBaseClasses = classSymbol :: addParentBaseClasses(classParents, Nil)
1328-
mySuperClassBits = seen.toImmutable
1336+
val bcs = classSymbol :: addParentBaseClasses(classParents, Nil)
1337+
val scbits = seen.toImmutable
1338+
if (isFullyCompleted) {
1339+
myBaseClasses = bcs
1340+
mySuperClassBits = scbits
1341+
}
1342+
else myBaseClasses = null
1343+
(bcs, scbits)
13291344
}
13301345

13311346
/** A bitset that contains the superId's of all base classes */
13321347
private def superClassBits(implicit ctx: Context): BitSet =
13331348
if (classParents.isEmpty) BitSet() // can happen when called too early in Namers
13341349
else {
13351350
checkBasesUpToDate()
1336-
if (mySuperClassBits == null) computeBases
1337-
mySuperClassBits
1351+
if (mySuperClassBits != null) mySuperClassBits else computeBases._2
13381352
}
13391353

13401354
/** The base classes of this class in linearization order,
@@ -1344,8 +1358,7 @@ object SymDenotations {
13441358
if (classParents.isEmpty) classSymbol :: Nil // can happen when called too early in Namers
13451359
else {
13461360
checkBasesUpToDate()
1347-
if (myBaseClasses == null) computeBases
1348-
myBaseClasses
1361+
if (myBaseClasses != null) myBaseClasses else computeBases._1
13491362
}
13501363

13511364
final override def derivesFrom(base: Symbol)(implicit ctx: Context): Boolean =
@@ -1378,9 +1391,9 @@ object SymDenotations {
13781391
while (ps.nonEmpty) {
13791392
val parent = ps.head.typeSymbol
13801393
parent.denot match {
1381-
case classd: ClassDenotation =>
1382-
fp.include(classd.memberFingerPrint)
1383-
parent.denot.setFlag(Frozen)
1394+
case parentDenot: ClassDenotation =>
1395+
fp.include(parentDenot.memberFingerPrint)
1396+
if (parentDenot.isFullyCompleted) parentDenot.setFlag(Frozen)
13841397
case _ =>
13851398
}
13861399
ps = ps.tail
@@ -1393,10 +1406,13 @@ object SymDenotations {
13931406
* not be used for package classes because cache never
13941407
* gets invalidated.
13951408
*/
1396-
def memberFingerPrint(implicit ctx: Context): FingerPrint = {
1397-
if (myMemberFingerPrint == FingerPrint.unknown) myMemberFingerPrint = computeMemberFingerPrint
1398-
myMemberFingerPrint
1399-
}
1409+
def memberFingerPrint(implicit ctx: Context): FingerPrint =
1410+
if (myMemberFingerPrint != FingerPrint.unknown) myMemberFingerPrint
1411+
else {
1412+
val fp = computeMemberFingerPrint
1413+
if (isFullyCompleted) myMemberFingerPrint = fp
1414+
fp
1415+
}
14001416

14011417
private[this] var myMemberCache: LRUCache[Name, PreDenotation] = null
14021418
private[this] var myMemberCachePeriod: Period = Nowhere

test/dotc/scala-collections.whitelist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140

141141
# breaks genMapLike https://github.com/lampepfl/dotty/issues/937
142142
#./scala-scala/src/library/scala/collection/GenTraversable.scala
143-
#./scala-scala/src/library/scala/collection/GenTraversableLike.scala
143+
./scala-scala/src/library/scala/collection/GenTraversableLike.scala
144144

145145
./scala-scala/src/library/scala/collection/GenTraversableOnce.scala
146146
./scala-scala/src/library/scala/collection/IndexedSeq.scala

0 commit comments

Comments
 (0)