Skip to content

Commit

Permalink
Fix deterministically adding additional interfaces
Browse files Browse the repository at this point in the history
When a class contains calls to 'super' for traits it does
not directly implement, these are added to the list of interfaces
of the generated class. Previously, because these interfaces were
determined using set logic, the ordering of that list was not
deterministic.

This makes the order deterministic assuming the order in which
these calls are registered using `registerSuperCall` in the
`CollectSuperCalls` phase is deterministic within each class.
This seems likely to me but it'd be great if someone could
confirm.

To add a test for this change, creating a class that has many
'additional' traits and checking they are generated in the right
order would make sense, but I couldn't find an obvious place for
such a test. Any recommendations?

Fixes #20496
  • Loading branch information
raboof committed Jun 18, 2024
1 parent c1b25d6 commit 03ff49d
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 7 deletions.
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,13 @@ class BTypesFromSymbols[I <: DottyBackendInterface](val int: I, val frontendAcce
val directlyInheritedTraits = sym.directlyInheritedTraits
val directlyInheritedTraitsSet = directlyInheritedTraits.toSet
val allBaseClasses = directlyInheritedTraits.iterator.flatMap(_.asClass.baseClasses.drop(1)).toSet
val superCalls = superCallsMap.getOrElse(sym, Set.empty)
val additional = (superCalls -- directlyInheritedTraitsSet).filter(_.is(Trait))
val superCalls = superCallsMap.getOrElse(sym, List.empty)
val superCallsSet = superCalls.toSet
val additional = superCalls.foldLeft(List())((acc, t) =>
if !acc.contains(t) && !directlyInheritedTraitsSet(t) && t.is(Trait) then acc :+ t else acc)
// if (additional.nonEmpty)
// println(s"$fullName: adding supertraits $additional")
directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t)) ++ additional
directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCallsSet(t)) ++ additional
}

val interfaces = classSym.superInterfaces.map(classBTypeFromSymbol)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import StdNames.nme
import NameKinds.{LazyBitMapName, LazyLocalName}
import Names.Name

class DottyBackendInterface(val superCallsMap: ReadOnlyMap[Symbol, Set[ClassSymbol]])(using val ctx: Context) {
class DottyBackendInterface(val superCallsMap: ReadOnlyMap[Symbol, List[ClassSymbol]])(using val ctx: Context) {

private val desugared = new java.util.IdentityHashMap[Type, tpd.Select]

Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ class GenBCode extends Phase { self =>

override def isRunnable(using Context) = super.isRunnable && !ctx.usedBestEffortTasty

private val superCallsMap = new MutableSymbolMap[Set[ClassSymbol]]
private val superCallsMap = new MutableSymbolMap[List[ClassSymbol]]
def registerSuperCall(sym: Symbol, calls: ClassSymbol): Unit = {
val old = superCallsMap.getOrElse(sym, Set.empty)
superCallsMap.update(sym, old + calls)
val old = superCallsMap.getOrElse(sym, List.empty)
superCallsMap.update(sym, old :+ calls)
}

private val entryPoints = new mutable.HashSet[String]()
Expand Down

0 comments on commit 03ff49d

Please sign in to comment.