diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt index 60f035137bc..a85e6e13c94 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt @@ -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.stableOrdered(): List { + val strictOrder = hashMapOf() + + 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.ordered(): List { - if (!stableOrder) return this - - val strictOrder = mutableMapOf() - - 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.ordered(): List = if (stableOrder) stableOrdered() else this override fun visitElement(element: IrElement, data: String) { element.dumpLabeledElementWith(data) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/dumpKotlinLike.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/dumpKotlinLike.kt index 141652bd5e8..ad0de3ebedc 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/dumpKotlinLike.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/dumpKotlinLike.kt @@ -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.ordered() = if (options.stableOrder) stableOrdered() else this + + @JvmName("orderedTypes") // Prevent JVM signature clash + private fun List.ordered(): List { + 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 {