[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
|
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(
|
class DumpIrTreeVisitor(
|
||||||
out: Appendable,
|
out: Appendable,
|
||||||
normalizeNames: Boolean = false,
|
normalizeNames: Boolean = false,
|
||||||
@@ -58,33 +89,7 @@ class DumpIrTreeVisitor(
|
|||||||
private val elementRenderer = RenderIrElementVisitor(normalizeNames, !stableOrder)
|
private val elementRenderer = RenderIrElementVisitor(normalizeNames, !stableOrder)
|
||||||
private fun IrType.render() = elementRenderer.renderType(this)
|
private fun IrType.render() = elementRenderer.renderType(this)
|
||||||
|
|
||||||
private fun List<IrDeclaration>.ordered(): List<IrDeclaration> {
|
private fun List<IrDeclaration>.ordered(): List<IrDeclaration> = if (stableOrder) stableOrdered() else this
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement, data: String) {
|
override fun visitElement(element: IrElement, data: String) {
|
||||||
element.dumpLabeledElementWith(data) {
|
element.dumpLabeledElementWith(data) {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class KotlinLikeDumpOptions(
|
|||||||
val printFakeOverridesStrategy: FakeOverridesStrategy = FakeOverridesStrategy.ALL,
|
val printFakeOverridesStrategy: FakeOverridesStrategy = FakeOverridesStrategy.ALL,
|
||||||
val bodyPrintingStrategy: BodyPrintingStrategy = BodyPrintingStrategy.PRINT_BODIES,
|
val bodyPrintingStrategy: BodyPrintingStrategy = BodyPrintingStrategy.PRINT_BODIES,
|
||||||
val printElseAsTrue: Boolean = false,
|
val printElseAsTrue: Boolean = false,
|
||||||
|
val stableOrder: Boolean = false,
|
||||||
/*
|
/*
|
||||||
TODO add more options:
|
TODO add more options:
|
||||||
always print visibility?
|
always print visibility?
|
||||||
@@ -166,6 +167,22 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
|
|||||||
typeArg.printTypeArgumentWithNoIndent()
|
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?) {
|
override fun visitElement(element: IrElement, data: IrDeclaration?) {
|
||||||
val e = "/* ERROR: unsupported element type: " + element.javaClass.simpleName + " */"
|
val e = "/* ERROR: unsupported element type: " + element.javaClass.simpleName + " */"
|
||||||
if (element is IrExpression) {
|
if (element is IrExpression) {
|
||||||
@@ -195,7 +212,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
|
|||||||
}
|
}
|
||||||
if (!p.isEmpty) p.printlnWithNoIndent()
|
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")
|
if (options.printRegionsPerFile) p.println("//endregion")
|
||||||
}
|
}
|
||||||
@@ -240,7 +257,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
|
|||||||
// TODO no test
|
// TODO no test
|
||||||
if (declaration.superTypes.isNotEmpty()) {
|
if (declaration.superTypes.isNotEmpty()) {
|
||||||
var first = true
|
var first = true
|
||||||
for (type in declaration.superTypes) {
|
for (type in declaration.superTypes.ordered()) {
|
||||||
if (type.isAny()) continue
|
if (type.isAny()) continue
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
@@ -260,7 +277,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
|
|||||||
p.printlnWithNoIndent(" {")
|
p.printlnWithNoIndent(" {")
|
||||||
p.pushIndent()
|
p.pushIndent()
|
||||||
|
|
||||||
declaration.declarations.forEach { it.accept(this, declaration) }
|
declaration.declarations.ordered().forEach { it.accept(this, declaration) }
|
||||||
|
|
||||||
p.popIndent()
|
p.popIndent()
|
||||||
p.println("}")
|
p.println("}")
|
||||||
@@ -431,7 +448,7 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
|
|||||||
|
|
||||||
private fun IrTypeParameter.printWhereClauseTypesWithNoIndent(first: Boolean): Boolean {
|
private fun IrTypeParameter.printWhereClauseTypesWithNoIndent(first: Boolean): Boolean {
|
||||||
var myFirst = first
|
var myFirst = first
|
||||||
superTypes.forEach { type ->
|
superTypes.ordered().forEach { type ->
|
||||||
if (!myFirst) {
|
if (!myFirst) {
|
||||||
p.printWithNoIndent(", ")
|
p.printWithNoIndent(", ")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user