[IR] Support stable ordering in Kotlin-like IR dump

This is needed for signature tests to work with the same golden data
on both K1 and K2, since sometimes K1 and K2 produce IR with different
order of declarations and supertypes.
This commit is contained in:
Sergej Jaskiewicz
2023-05-04 18:34:21 +02:00
committed by Space Team
parent 71e81aa30e
commit bfa2c92c7f
2 changed files with 53 additions and 31 deletions
@@ -48,6 +48,37 @@ private fun IrFile.shouldSkipDump(): Boolean {
return entry.lineStartOffsetsAreEmpty
}
/**
* Sorts the declarations in the list using the result of [IrDeclaration.render] as the sorting key.
*
* The exception is properties with backing fields and [IrAnonymousInitializer]s: their relative order is preserved.
*/
internal fun List<IrDeclaration>.stableOrdered(): List<IrDeclaration> {
val strictOrder = hashMapOf<IrDeclaration, Int>()
var idx = 0
forEach {
if (it is IrProperty && it.backingField != null && !it.isConst) {
strictOrder[it] = idx++
}
if (it is IrAnonymousInitializer) {
strictOrder[it] = idx++
}
}
return sortedWith { a, b ->
val strictA = strictOrder[a] ?: Int.MAX_VALUE
val strictB = strictOrder[b] ?: Int.MAX_VALUE
if (strictA == strictB) {
val rA = a.render()
val rB = b.render()
rA.compareTo(rB)
} else strictA - strictB
}
}
class DumpIrTreeVisitor(
out: Appendable,
normalizeNames: Boolean = false,
@@ -58,33 +89,7 @@ class DumpIrTreeVisitor(
private val elementRenderer = RenderIrElementVisitor(normalizeNames, !stableOrder)
private fun IrType.render() = elementRenderer.renderType(this)
private fun List<IrDeclaration>.ordered(): List<IrDeclaration> {
if (!stableOrder) return this
val strictOrder = mutableMapOf<IrDeclaration, Int>()
var idx = 0
forEach {
if (it is IrProperty && it.backingField != null && !it.isConst) {
strictOrder[it] = idx++
}
if (it is IrAnonymousInitializer) {
strictOrder[it] = idx++
}
}
return sortedWith { a, b ->
val strictA = strictOrder[a] ?: Int.MAX_VALUE
val strictB = strictOrder[b] ?: Int.MAX_VALUE
if (strictA == strictB) {
val rA = a.render()
val rB = b.render()
rA.compareTo(rB)
} else strictA - strictB
}
}
private fun List<IrDeclaration>.ordered(): List<IrDeclaration> = if (stableOrder) stableOrdered() else this
override fun visitElement(element: IrElement, data: String) {
element.dumpLabeledElementWith(data) {
@@ -66,6 +66,7 @@ class KotlinLikeDumpOptions(
val printFakeOverridesStrategy: FakeOverridesStrategy = FakeOverridesStrategy.ALL,
val bodyPrintingStrategy: BodyPrintingStrategy = BodyPrintingStrategy.PRINT_BODIES,
val printElseAsTrue: Boolean = false,
val stableOrder: Boolean = false,
/*
TODO add more options:
always print visibility?
@@ -166,6 +167,22 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
typeArg.printTypeArgumentWithNoIndent()
}
@JvmName("orderedDeclarations") // Prevent JVM signature clash
private fun List<IrDeclaration>.ordered() = if (options.stableOrder) stableOrdered() else this
@JvmName("orderedTypes") // Prevent JVM signature clash
private fun List<IrType>.ordered(): List<IrType> {
if (!options.stableOrder) return this
fun isNonInterfaceType(type: IrType) = type.classifierOrNull?.let {
it !is IrClassSymbol || !it.owner.isInterface
} ?: true
val (classTypes, interfaceTypes) = partition(::isNonInterfaceType)
return classTypes.sortedBy(IrType::render) + interfaceTypes.sortedBy(IrType::render)
}
override fun visitElement(element: IrElement, data: IrDeclaration?) {
val e = "/* ERROR: unsupported element type: " + element.javaClass.simpleName + " */"
if (element is IrExpression) {
@@ -195,7 +212,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
}
if (!p.isEmpty) p.printlnWithNoIndent()
declaration.declarations.forEach { it.accept(this, null) }
declaration.declarations.ordered().forEach { it.accept(this, null) }
if (options.printRegionsPerFile) p.println("//endregion")
}
@@ -240,7 +257,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
// TODO no test
if (declaration.superTypes.isNotEmpty()) {
var first = true
for (type in declaration.superTypes) {
for (type in declaration.superTypes.ordered()) {
if (type.isAny()) continue
if (!first) {
@@ -260,7 +277,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
p.printlnWithNoIndent(" {")
p.pushIndent()
declaration.declarations.forEach { it.accept(this, declaration) }
declaration.declarations.ordered().forEach { it.accept(this, declaration) }
p.popIndent()
p.println("}")
@@ -431,7 +448,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
private fun IrTypeParameter.printWhereClauseTypesWithNoIndent(first: Boolean): Boolean {
var myFirst = first
superTypes.forEach { type ->
superTypes.ordered().forEach { type ->
if (!myFirst) {
p.printWithNoIndent(", ")
} else {