[backend] Allow argument reordering in enum entry initializers (#1794)

This commit is contained in:
ilmat192
2018-07-13 15:33:24 +07:00
committed by GitHub
parent 5879784536
commit a83a48930b
3 changed files with 99 additions and 12 deletions
@@ -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 {
+4
View File
@@ -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)
}