[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:
committed by
Space Team
parent
71e81aa30e
commit
bfa2c92c7f
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user