From 10e79bff8bca82d5e24474fd8611a7bc96eb7828 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Wed, 24 Feb 2021 11:31:20 +0500 Subject: [PATCH] [IR] Fixed bug with wrong init order of a enum's entries This fixes https://youtrack.jetbrains.com/issue/KT-38540 (cherry picked from commit d031526a6e1a618597898dd6beadb04eed74b478) --- .../backend/konan/lower/EnumClassLowering.kt | 40 ++++--- .../tests/codegen/enum/kt38540.kt | 107 ++++++++++++++++++ 2 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 kotlin-native/backend.native/tests/codegen/enum/kt38540.kt diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index 21f6779a58c..65147293a54 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -282,29 +282,27 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { val valuesInitializer = irBuilder.irBlock(startOffset, endOffset) { val receiver = implObject.thisReceiver!! val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField)) - enumEntries - .sortedBy { it.name } - .withIndex() - .forEach { - val instance = irCall(arrayGetSymbol).apply { - dispatchReceiver = irGet(instances) - putValueArgument(0, irInt(it.index)) - } - val initializer = it.value.initializerExpression!!.expression - initializer.setDeclarationsParent(constructor) - when { - initializer is IrConstructorCall -> +initInstanceCall(instance, initializer) + val enumIndices = enumEntries.sortedBy { it.name }.withIndex().associate { it.value to it.index } + enumEntries.forEach { + val instance = irCall(arrayGetSymbol).apply { + dispatchReceiver = irGet(instances) + putValueArgument(0, irInt(enumIndices[it]!!)) + } + val initializer = it.initializerExpression!!.expression + initializer.setDeclarationsParent(constructor) + when { + initializer is IrConstructorCall -> +initInstanceCall(instance, initializer) - initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { - val statements = initializer.statements - val constructorCall = statements.last() as IrConstructorCall - statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) - +initializer - } - - else -> error("Unexpected initializer: $initializer") - } + initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { + val statements = initializer.statements + val constructorCall = statements.last() as IrConstructorCall + statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) + +initializer } + + else -> error("Unexpected initializer: $initializer") + } + } +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply { extensionReceiver = irGet(receiver) } diff --git a/kotlin-native/backend.native/tests/codegen/enum/kt38540.kt b/kotlin-native/backend.native/tests/codegen/enum/kt38540.kt new file mode 100644 index 00000000000..ec2e8d43570 --- /dev/null +++ b/kotlin-native/backend.native/tests/codegen/enum/kt38540.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package codegen.enum.kt38540 + +import kotlin.test.* + +public enum class Node( + public val external: Boolean, + public val dependsOn: Set, + public val required: Boolean +) { + A( + external = false, + dependsOn = emptySet(), + required = true + ), + B( + external = false, + dependsOn = emptySet(), + required = true + ), + C( + external = true, + dependsOn = emptySet(), + required = true + ), + D( + external = true, + dependsOn = emptySet(), + required = true + ), + E( + external = true, + dependsOn = emptySet(), + required = true + ), + F( + external = true, + dependsOn = emptySet(), + required = true + ), + G( + external = true, + dependsOn = emptySet(), + required = false + ), + H( + external = true, + dependsOn = emptySet(), + required = true + ), + I( + external = true, + dependsOn = emptySet(), + required = true + ), + J( + external = true, + dependsOn = emptySet(), + required = true + ), + K( + external = true, + dependsOn = setOf(I), + required = true + ), + L( + external = true, + dependsOn = setOf(I), + required = true + ), + M( + external = true, + dependsOn = setOf(I), + required = true + ), + N( + external = true, + dependsOn = emptySet(), + required = true + ), + O( + external = true, + dependsOn = emptySet(), + required = true + ), + AG( + external = true, + dependsOn = emptySet(), + required = true + ), + FIELD_REPORT( + external = true, + dependsOn = setOf(AG, O, J), + required = true + ) +} + +@Test +fun runTest() { + assertTrue(Node.FIELD_REPORT.dependsOn.contains(Node.AG)) + assertTrue(Node.FIELD_REPORT.dependsOn.contains(Node.O)) + assertTrue(Node.FIELD_REPORT.dependsOn.contains(Node.J)) +} \ No newline at end of file