[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)
This commit is contained in:
Igor Chevdar
2021-02-24 11:31:20 +05:00
committed by Space
parent 31835f1921
commit 10e79bff8b
2 changed files with 126 additions and 21 deletions
@@ -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)
}
@@ -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<Node>,
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))
}