IR: move enum value array initialization out of <clinit>
#KT-44192 Fixed
This commit is contained in:
committed by
Alexander Udalov
parent
f8f08e8134
commit
7cc06489dd
+28
-9
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
|||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -46,6 +47,8 @@ internal val enumClassPhase = makeIrFilePhase(
|
|||||||
description = "Handle enum classes"
|
description = "Handle enum classes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private const val VALUES_HELPER_FUNCTION_NAME = "\$values"
|
||||||
|
|
||||||
private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
if (!irClass.isEnumClass) return
|
if (!irClass.isEnumClass) return
|
||||||
@@ -69,13 +72,16 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
irClass.declarations.removeAll { it is IrEnumEntry }
|
irClass.declarations.removeAll { it is IrEnumEntry }
|
||||||
irClass.declarations += declarationToEnumEntry.keys
|
irClass.declarations += declarationToEnumEntry.keys
|
||||||
|
|
||||||
// Construct the synthetic $VALUES field, which contains an array of all enum entries
|
// Construct the synthetic $values() function, which creates an array of all enum entries
|
||||||
val valuesField = buildValuesField()
|
val valuesHelperFunction = buildValuesHelperFunction()
|
||||||
|
|
||||||
|
// Construct the synthetic $VALUES field, which contains an array of all enum entries by calling $values()
|
||||||
|
val valuesField = buildValuesField(valuesHelperFunction)
|
||||||
|
|
||||||
// Add synthetic parameters to enum constructors and implement the values and valueOf functions
|
// Add synthetic parameters to enum constructors and implement the values and valueOf functions
|
||||||
irClass.transformChildrenVoid(EnumClassDeclarationsTransformer(valuesField))
|
irClass.transformChildrenVoid(EnumClassDeclarationsTransformer(valuesField))
|
||||||
|
|
||||||
// Add synthetic arguments to enum constructor calls and remap enum constructor paramters
|
// Add synthetic arguments to enum constructor calls and remap enum constructor parameters
|
||||||
irClass.transformChildrenVoid(EnumClassCallTransformer())
|
irClass.transformChildrenVoid(EnumClassCallTransformer())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +91,22 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
annotations += enumEntry.annotations
|
annotations += enumEntry.annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildValuesField(): IrField = irClass.addField {
|
private fun buildValuesHelperFunction(): IrFunction = irClass.addFunction {
|
||||||
|
name = Name.identifier(VALUES_HELPER_FUNCTION_NAME)
|
||||||
|
returnType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
||||||
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
|
origin = IrDeclarationOrigin.SYNTHETIC_HELPER_FOR_ENUM_VALUES
|
||||||
|
}.apply {
|
||||||
|
body = context.createJvmIrBuilder(symbol).run {
|
||||||
|
irExprBody(irArray(returnType) {
|
||||||
|
for (irField in declarationToEnumEntry.keys.filterIsInstance<IrField>()) {
|
||||||
|
+irGetField(null, irField)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildValuesField(valuesHelperFunction: IrFunction): IrField = irClass.addField {
|
||||||
name = Name.identifier(ImplementationBodyCodegen.ENUM_VALUES_FIELD_NAME)
|
name = Name.identifier(ImplementationBodyCodegen.ENUM_VALUES_FIELD_NAME)
|
||||||
type = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
type = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
||||||
visibility = DescriptorVisibilities.PRIVATE
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
@@ -94,11 +115,9 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
isStatic = true
|
isStatic = true
|
||||||
}.apply {
|
}.apply {
|
||||||
initializer = context.createJvmIrBuilder(symbol).run {
|
initializer = context.createJvmIrBuilder(symbol).run {
|
||||||
irExprBody(irArray(type) {
|
irExprBody(
|
||||||
for (irField in declarationToEnumEntry.keys.filterIsInstance<IrField>()) {
|
irCall(valuesHelperFunction.symbol)
|
||||||
+irGetField(null, irField)
|
)
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ interface IrDeclarationOrigin {
|
|||||||
object BRIDGE_SPECIAL : IrDeclarationOriginImpl("BRIDGE_SPECIAL")
|
object BRIDGE_SPECIAL : IrDeclarationOriginImpl("BRIDGE_SPECIAL")
|
||||||
|
|
||||||
object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY")
|
object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY")
|
||||||
|
object SYNTHETIC_HELPER_FOR_ENUM_VALUES : IrDeclarationOriginImpl("SYNTHETIC_HELPER_FOR_ENUM_VALUES", isSynthetic = true)
|
||||||
object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES", isSynthetic = true)
|
object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES", isSynthetic = true)
|
||||||
object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE")
|
object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE")
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM
|
// IGNORE_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
|
|
||||||
enum class BigEnum {
|
enum class BigEnum {
|
||||||
C0001, C0002, C0003, C0004, C0005, C0006, C0007, C0008, C0009, C0010,
|
C0001, C0002, C0003, C0004, C0005, C0006, C0007, C0008, C0009, C0010,
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class Test {
|
||||||
|
// source: 'deprecatedEnumEntryFields.kt'
|
||||||
|
private synthetic final static field $VALUES: Test[]
|
||||||
|
public deprecated final enum static @kotlin.Deprecated field ENTRY1: Test
|
||||||
|
public final enum static field ENTRY2: Test
|
||||||
|
public deprecated final enum static @kotlin.Deprecated field ENTRY3: Test
|
||||||
|
private synthetic final static method $values(): Test[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public static method valueOf(p0: java.lang.String): Test
|
||||||
|
public static method values(): Test[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
@java.lang.annotation.Retention
|
||||||
|
@kotlin.Metadata
|
||||||
|
public annotation class Ann {
|
||||||
|
// source: 'enum.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class SimpleEnum {
|
||||||
|
// source: 'enum.kt'
|
||||||
|
private synthetic final static field $VALUES: SimpleEnum[]
|
||||||
|
public final enum static field A: SimpleEnum
|
||||||
|
public final enum static field B: SimpleEnum
|
||||||
|
public final enum static field C: SimpleEnum
|
||||||
|
private synthetic final static method $values(): SimpleEnum[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public static method valueOf(p0: java.lang.String): SimpleEnum
|
||||||
|
public static method values(): SimpleEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class WithAnnotations {
|
||||||
|
// source: 'enum.kt'
|
||||||
|
private synthetic final static field $VALUES: WithAnnotations[]
|
||||||
|
public final enum static @Ann field A: WithAnnotations
|
||||||
|
public final enum static @Ann field B: WithAnnotations
|
||||||
|
private synthetic final static method $values(): WithAnnotations[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public static method valueOf(p0: java.lang.String): WithAnnotations
|
||||||
|
public static method values(): WithAnnotations[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class WithConstructor {
|
||||||
|
// source: 'enum.kt'
|
||||||
|
private synthetic final static field $VALUES: WithConstructor[]
|
||||||
|
public final enum static field A: WithConstructor
|
||||||
|
public final enum static field B: WithConstructor
|
||||||
|
public final enum static field C: WithConstructor
|
||||||
|
private final @org.jetbrains.annotations.NotNull field x: java.lang.String
|
||||||
|
private synthetic final static method $values(): WithConstructor[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int, p2: java.lang.String): void
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getX(): java.lang.String
|
||||||
|
public static method valueOf(p0: java.lang.String): WithConstructor
|
||||||
|
public static method values(): WithConstructor[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
final class WithEntryClass$A {
|
||||||
|
// source: 'enum.kt'
|
||||||
|
final inner class WithEntryClass$A
|
||||||
|
method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public method foo(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public abstract enum class WithEntryClass {
|
||||||
|
// source: 'enum.kt'
|
||||||
|
private synthetic final static field $VALUES: WithEntryClass[]
|
||||||
|
public final enum static field A: WithEntryClass
|
||||||
|
final inner class WithEntryClass$A
|
||||||
|
private synthetic final static method $values(): WithEntryClass[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public synthetic method <init>(p0: java.lang.String, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public abstract method foo(): void
|
||||||
|
public static method valueOf(p0: java.lang.String): WithEntryClass
|
||||||
|
public static method values(): WithEntryClass[]
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public interface PrivateMarker {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public interface ProtectedMarker {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public interface PublicMarker {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public class TestBasic {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
private final field z: int
|
||||||
|
private method <init>(p0: int): void
|
||||||
|
private method <init>(p0: int, p1: PrivateMarker): void
|
||||||
|
private method <init>(p0: int, p1: ProtectedMarker): void
|
||||||
|
public synthetic method <init>(p0: int, p1: ProtectedMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
private method <init>(p0: int, p1: PublicMarker): void
|
||||||
|
public synthetic method <init>(p0: int, p1: PublicMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public synthetic method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public final method getZ-a_XrcN0(): int
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class TestEnum {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
private synthetic final static field $VALUES: TestEnum[]
|
||||||
|
public final enum static field ANSWER: TestEnum
|
||||||
|
private final field z: int
|
||||||
|
private synthetic final static method $values(): TestEnum[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int, p2: int): void
|
||||||
|
public final method getZ-a_XrcN0(): int
|
||||||
|
public static method valueOf(p0: java.lang.String): TestEnum
|
||||||
|
public static method values(): TestEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class TestInner$Inner {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
synthetic final field this$0: TestInner
|
||||||
|
private final field z: int
|
||||||
|
private method <init>(p0: TestInner, p1: int): void
|
||||||
|
public synthetic method <init>(p0: TestInner, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public final method getZ-a_XrcN0(): int
|
||||||
|
public final inner class TestInner$Inner
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class TestInner {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
public method <init>(): void
|
||||||
|
public final inner class TestInner$Inner
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class TestSealed$Case {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
private method <init>(p0: int): void
|
||||||
|
public synthetic method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public final inner class TestSealed$Case
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public abstract class TestSealed {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
private final field z: int
|
||||||
|
private method <init>(p0: int): void
|
||||||
|
public synthetic method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public final method getZ-a_XrcN0(): int
|
||||||
|
public final inner class TestSealed$Case
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.JvmInline
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class Z {
|
||||||
|
// source: 'inlineClassTypeParametersInConstructor.kt'
|
||||||
|
private final field x: int
|
||||||
|
private synthetic method <init>(p0: int): void
|
||||||
|
public synthetic final static method box-impl(p0: int): Z
|
||||||
|
public static method constructor-impl(p0: int): int
|
||||||
|
public method equals(p0: java.lang.Object): boolean
|
||||||
|
public static method equals-impl(p0: int, p1: java.lang.Object): boolean
|
||||||
|
public final static method equals-impl0(p0: int, p1: int): boolean
|
||||||
|
public final method getX(): int
|
||||||
|
public method hashCode(): int
|
||||||
|
public static method hashCode-impl(p0: int): int
|
||||||
|
public method toString(): java.lang.String
|
||||||
|
public static method toString-impl(p0: int): java.lang.String
|
||||||
|
public synthetic final method unbox-impl(): int
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
@NoArg
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class Colors {
|
||||||
|
// source: 'annoOnNotClass.kt'
|
||||||
|
private synthetic final static field $VALUES: Colors[]
|
||||||
|
public final enum static field RED: Colors
|
||||||
|
public final enum static field WHITE: Colors
|
||||||
|
private synthetic final static method $values(): Colors[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public static method valueOf(p0: java.lang.String): Colors
|
||||||
|
public static method values(): Colors[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoArg
|
||||||
|
@kotlin.Metadata
|
||||||
|
public interface Intf {
|
||||||
|
// source: 'annoOnNotClass.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class MyClass {
|
||||||
|
// source: 'annoOnNotClass.kt'
|
||||||
|
private @NoArg @org.jetbrains.annotations.NotNull field abc: java.lang.String
|
||||||
|
public method <init>(p0: int): void
|
||||||
|
public final @NoArg @org.jetbrains.annotations.NotNull method getAbc(): java.lang.String
|
||||||
|
public final @NoArg method setAbc(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||||
|
public final @NoArg method someFun(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoArg
|
||||||
|
@java.lang.annotation.Retention
|
||||||
|
@kotlin.Metadata
|
||||||
|
public annotation class NoArg {
|
||||||
|
// source: 'annoOnNotClass.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoArg
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class Obj {
|
||||||
|
// source: 'annoOnNotClass.kt'
|
||||||
|
public final static @org.jetbrains.annotations.NotNull field INSTANCE: Obj
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(): void
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user