diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index c196972ff90..c30e9b0a875 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -19,20 +19,16 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.deepCopyWithVariables +import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName -import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor -import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement @@ -40,6 +36,7 @@ import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol @@ -333,7 +330,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { enumEntries .sortedBy { it.descriptor.name } .map { - val entryConstructorCall = it.initializerExpression!! as IrCall + val initializer = it.initializerExpression + val entryConstructorCall = when { + initializer is IrCall -> initializer + initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> + initializer.statements.last() as IrCall + else -> error("Unexpected initializer: $initializer") + } val entryConstructor = entryConstructorCall.symbol.owner as IrConstructor val entryClass = entryConstructor.constructedClass @@ -383,6 +386,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { val startOffset = irClass.startOffset val endOffset = irClass.endOffset + fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall = + irCall(initInstanceSymbol).apply { + putValueArgument(0, instance) + putValueArgument(1, constructor) + } + return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply { body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) { val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!), loweredEnum.valuesField)) @@ -394,10 +403,16 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { dispatchReceiver = irGet(instances) putValueArgument(0, irInt(it.index)) } - val initializer = it.value.initializerExpression!! as IrCall - +irCall(initInstanceSymbol).apply { - putValueArgument(0, instance) - putValueArgument(1, initializer) + val initializer = it.value.initializerExpression!! + when { + initializer is IrCall -> +initInstanceCall(instance, initializer) + initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { + val statements = initializer.statements + val constructorCall = statements.last() as IrCall + statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) + +initializer + } + else -> error("Unexpected initializer: $initializer") } } +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply { diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index c190f4391f8..eda8d109c0a 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -807,6 +807,10 @@ task enum_loop(type: RunKonanTest) { source = "codegen/enum/loop.kt" } +task enum_reorderedArguments(type: RunKonanTest) { + source = "codegen/enum/reorderedArguments.kt" +} + task switchLowering(type: RunKonanTest) { goldValue = "EnumA.A\nok\nok\nok\nok\nok\n" source = "codegen/enum/switchLowering.kt" diff --git a/backend.native/tests/codegen/enum/reorderedArguments.kt b/backend.native/tests/codegen/enum/reorderedArguments.kt new file mode 100644 index 00000000000..94fc86f8d69 --- /dev/null +++ b/backend.native/tests/codegen/enum/reorderedArguments.kt @@ -0,0 +1,68 @@ +package codegen.enum.reorderedArguments + +import kotlin.test.* + +// Regression test for https://github.com/JetBrains/kotlin-native/issues/1779 +enum class Foo(val a: Int, val b: Int, val c: Int = 0) { + A(a = 1, b = 0), + B(b = 1, a = 0), + C(c = 1, b = 0, a = 0), + D(0, 0), + E(1, 1, 1) +} + +interface Base { + val value: T +} + +enum class Bar(override val value: Foo) : Base { + A(Foo.A), + B(Foo.B), + C(Foo.C), + D(Foo.D), + E(Foo.E) +} + +@Test fun runTest() { + + assertEquals(Foo.A.a, 1) + assertEquals(Foo.A.b, 0) + assertEquals(Foo.A.c, 0) + + assertEquals(Foo.B.a, 0) + assertEquals(Foo.B.b, 1) + assertEquals(Foo.B.c, 0) + + assertEquals(Foo.C.a, 0) + assertEquals(Foo.C.b, 0) + assertEquals(Foo.C.c, 1) + + assertEquals(Foo.D.a, 0) + assertEquals(Foo.D.b, 0) + assertEquals(Foo.D.c, 0) + + assertEquals(Foo.E.a, 1) + assertEquals(Foo.E.b, 1) + assertEquals(Foo.E.c, 1) + + assertEquals(Bar.A.value.a, 1) + assertEquals(Bar.A.value.b, 0) + assertEquals(Bar.A.value.c, 0) + + assertEquals(Bar.B.value.a, 0) + assertEquals(Bar.B.value.b, 1) + assertEquals(Bar.B.value.c, 0) + + assertEquals(Bar.C.value.a, 0) + assertEquals(Bar.C.value.b, 0) + assertEquals(Bar.C.value.c, 1) + + assertEquals(Bar.D.value.a, 0) + assertEquals(Bar.D.value.b, 0) + assertEquals(Bar.D.value.c, 0) + + assertEquals(Bar.E.value.a, 1) + assertEquals(Bar.E.value.b, 1) + assertEquals(Bar.E.value.c, 1) + +} \ No newline at end of file