Skip to content

Commit fe9d465

Browse files
committed
Fix deterministically adding additional interfaces
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 change makes the order deterministic (assuming the order in which these calls are registered using `registerSuperCall` in the `CollectSuperCalls` phase is deterministic within each class) Fixes #20496 [Cherry-picked 7500b05][modified]
1 parent 96793ee commit fe9d465

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

Diff for: compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala

+4-3
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,12 @@ class BTypesFromSymbols[I <: DottyBackendInterface](val int: I, val frontendAcce
112112
val directlyInheritedTraits = sym.directlyInheritedTraits
113113
val directlyInheritedTraitsSet = directlyInheritedTraits.toSet
114114
val allBaseClasses = directlyInheritedTraits.iterator.flatMap(_.asClass.baseClasses.drop(1)).toSet
115-
val superCalls = superCallsMap.getOrElse(sym, Set.empty)
116-
val additional = (superCalls -- directlyInheritedTraitsSet).filter(_.is(Trait))
115+
val superCalls = superCallsMap.getOrElse(sym, List.empty)
116+
val superCallsSet = superCalls.toSet
117+
val additional = superCalls.filter(t => !directlyInheritedTraitsSet(t) && t.is(Trait))
117118
// if (additional.nonEmpty)
118119
// println(s"$fullName: adding supertraits $additional")
119-
directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t)) ++ additional
120+
directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCallsSet(t)) ++ additional
120121
}
121122

122123
val interfaces = classSym.superInterfaces.map(classBTypeFromSymbol)

Diff for: compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import StdNames.nme
2525
import NameKinds.{LazyBitMapName, LazyLocalName}
2626
import Names.Name
2727

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

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

Diff for: compiler/src/dotty/tools/backend/jvm/GenBCode.scala

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ class GenBCode extends Phase { self =>
1616

1717
override def description: String = GenBCode.description
1818

19-
private val superCallsMap = new MutableSymbolMap[Set[ClassSymbol]]
19+
private val superCallsMap = new MutableSymbolMap[List[ClassSymbol]]
2020
def registerSuperCall(sym: Symbol, calls: ClassSymbol): Unit = {
21-
val old = superCallsMap.getOrElse(sym, Set.empty)
22-
superCallsMap.update(sym, old + calls)
21+
val old = superCallsMap.getOrElse(sym, List.empty)
22+
if (!old.contains(calls))
23+
superCallsMap.update(sym, old :+ calls)
2324
}
2425

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

Diff for: compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

+24
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,30 @@ class DottyBytecodeTests extends DottyBytecodeTest {
19631963
assertSameCode(instructions, expected)
19641964
}
19651965
}
1966+
1967+
/**
1968+
* Test 'additional' imports are generated in deterministic order
1969+
* https://github.com/scala/scala3/issues/20496
1970+
*/
1971+
@Test def deterministicAdditionalImports = {
1972+
val source =
1973+
"""trait Actor:
1974+
| def receive() = ()
1975+
|trait Timers:
1976+
| def timers() = ()
1977+
|abstract class ShardCoordinator extends Actor with Timers
1978+
|class PersistentShardCoordinator extends ShardCoordinator:
1979+
| def foo =
1980+
| super.receive()
1981+
| super.timers()""".stripMargin
1982+
checkBCode(source) { dir =>
1983+
val clsIn = dir.lookupName("PersistentShardCoordinator.class", directory = false).input
1984+
val clsNode = loadClassNode(clsIn)
1985+
1986+
val expected = List("Actor", "Timers")
1987+
assertEquals(expected, clsNode.interfaces.asScala)
1988+
}
1989+
}
19661990
}
19671991

19681992
object invocationReceiversTestCode {

0 commit comments

Comments
 (0)