[backend] Allow argument reordering in enum entry initializers (#1794)
This commit is contained in:
+27
-12
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<T> {
|
||||
val value: T
|
||||
}
|
||||
|
||||
enum class Bar(override val value: Foo) : Base<Foo> {
|
||||
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)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user