[JVM] Support Enum.entries for enums being compiled with Kotlin 1.8+
#KT-53236
This commit is contained in:
committed by
Space
parent
1b6a43ba69
commit
e708809e55
+6
@@ -16281,6 +16281,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumConstructorParameterClashWithDefaults.kt");
|
runTest("compiler/testData/codegen/box/enum/enumConstructorParameterClashWithDefaults.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntries.kt")
|
||||||
|
public void testEnumEntries() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntries.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumEntryMembers.kt")
|
@TestMetadata("enumEntryMembers.kt")
|
||||||
public void testEnumEntryMembers() throws Exception {
|
public void testEnumEntryMembers() throws Exception {
|
||||||
|
|||||||
+6
@@ -2194,6 +2194,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt");
|
runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntries.kt")
|
||||||
|
public void testEnumEntries() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/enum/enumEntries.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt18731.kt")
|
@TestMetadata("kt18731.kt")
|
||||||
public void testKt18731() throws Exception {
|
public void testKt18731() throws Exception {
|
||||||
|
|||||||
+137
-16
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -14,23 +14,23 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
|||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.irArray
|
import org.jetbrains.kotlin.backend.jvm.ir.irArray
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference
|
import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference
|
||||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
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.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.types.getClass
|
||||||
import org.jetbrains.kotlin.ir.types.typeWith
|
import org.jetbrains.kotlin.ir.types.typeWith
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
@@ -45,18 +45,59 @@ internal val enumClassPhase = makeIrFilePhase(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private const val VALUES_HELPER_FUNCTION_NAME = "\$values"
|
private const val VALUES_HELPER_FUNCTION_NAME = "\$values"
|
||||||
|
private const val ENTRIES_HELPER_FUNCTION_NAME = "\$entries"
|
||||||
|
private const val ENTRIES_FIELD_NAME = "\$ENTRIES"
|
||||||
|
|
||||||
|
private class EnumClassLowering(private val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Example of codegen for
|
||||||
|
* `enum class MyEnum { A }`
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* enum MyEnum extends Enum<MyEnum> {
|
||||||
|
* private static final synthetic MyEnum[] $VALUES
|
||||||
|
* private static final synthetic List<MyEnum> $ENTRIES;
|
||||||
|
*
|
||||||
|
* <clinit> {
|
||||||
|
* A = new MyEnum("A", 0);
|
||||||
|
* $VALUES = $values();
|
||||||
|
* Function0<MyEnum[]> supplier = #invokedynamic ..args.. $entries;
|
||||||
|
* $ENTRIES = new EnumEntriesList(supplier);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public static MyEnum[] values() {
|
||||||
|
* return $VALUES.clone();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Should be RO property from Kotlin standpoint
|
||||||
|
* public static List<MyEnum> getEntries() {
|
||||||
|
* return $ENTRIES;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* private synthetic static MyEnum[] $values() {
|
||||||
|
* return new MyEnum[] { A };
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* private synthetic static MyEnum[] $entries() {
|
||||||
|
* return $VALUES
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
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
|
||||||
EnumClassTransformer(irClass).run()
|
// Also protected by API version check as it relies on EnumEntries in standard library
|
||||||
|
EnumClassTransformer(irClass, context.state.languageVersionSettings.supportsFeature(LanguageFeature.EnumEntries)).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class EnumClassTransformer(val irClass: IrClass) {
|
private inner class EnumClassTransformer(private val irClass: IrClass, private val supportsEnumEntries: Boolean) {
|
||||||
private val loweredEnumConstructors = hashMapOf<IrConstructorSymbol, IrConstructor>()
|
private val loweredEnumConstructors = hashMapOf<IrConstructorSymbol, IrConstructor>()
|
||||||
private val loweredEnumConstructorParameters = hashMapOf<IrValueParameterSymbol, IrValueParameter>()
|
private val loweredEnumConstructorParameters = hashMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||||
private val enumEntryOrdinals = TObjectIntHashMap<IrEnumEntry>()
|
private val enumEntryOrdinals = TObjectIntHashMap<IrEnumEntry>()
|
||||||
private val declarationToEnumEntry = mutableMapOf<IrDeclaration, IrEnumEntry>()
|
private val declarationToEnumEntry = mutableMapOf<IrDeclaration, IrEnumEntry>()
|
||||||
|
private val enumArrayType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType) // Enum[]
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
// Lower IrEnumEntry into IrField and IrClass members
|
// Lower IrEnumEntry into IrField and IrClass members
|
||||||
@@ -75,8 +116,25 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
// Construct the synthetic $VALUES field, which contains an array of all enum entries by calling $values()
|
// Construct the synthetic $VALUES field, which contains an array of all enum entries by calling $values()
|
||||||
val valuesField = buildValuesField(valuesHelperFunction)
|
val valuesField = buildValuesField(valuesHelperFunction)
|
||||||
|
|
||||||
|
val entriesField: IrField?
|
||||||
|
if (supportsEnumEntries) {
|
||||||
|
// Constructs the synthetic $entries() function that returns plain $VALUES without copy
|
||||||
|
val entriesHelperFunction = buildEntriesHelperFunction(valuesField)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add synthetic $ENTRIES field and binds its initializer to
|
||||||
|
* ```
|
||||||
|
* val supplier: () -> E[] = indy LMF $entries
|
||||||
|
* $ENTRIES = EnumEntries(supplier)
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
entriesField = buildEntriesField(entriesHelperFunction)
|
||||||
|
} else {
|
||||||
|
entriesField = null
|
||||||
|
}
|
||||||
|
|
||||||
// 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, entriesField))
|
||||||
|
|
||||||
// Add synthetic arguments to enum constructor calls and remap enum constructor parameters
|
// Add synthetic arguments to enum constructor calls and remap enum constructor parameters
|
||||||
irClass.transformChildrenVoid(EnumClassCallTransformer())
|
irClass.transformChildrenVoid(EnumClassCallTransformer())
|
||||||
@@ -85,12 +143,12 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
private fun buildEnumEntryField(enumEntry: IrEnumEntry): IrField =
|
private fun buildEnumEntryField(enumEntry: IrEnumEntry): IrField =
|
||||||
context.cachedDeclarations.getFieldForEnumEntry(enumEntry).apply {
|
context.cachedDeclarations.getFieldForEnumEntry(enumEntry).apply {
|
||||||
initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!.expression.patchDeclarationParents(this))
|
initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!.expression.patchDeclarationParents(this))
|
||||||
annotations += enumEntry.annotations
|
annotations = annotations + enumEntry.annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildValuesHelperFunction(): IrFunction = irClass.addFunction {
|
private fun buildValuesHelperFunction(): IrFunction = irClass.addFunction {
|
||||||
name = Name.identifier(VALUES_HELPER_FUNCTION_NAME)
|
name = Name.identifier(VALUES_HELPER_FUNCTION_NAME)
|
||||||
returnType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
returnType = enumArrayType
|
||||||
visibility = DescriptorVisibilities.PRIVATE
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
origin = IrDeclarationOrigin.SYNTHETIC_HELPER_FOR_ENUM_VALUES
|
origin = IrDeclarationOrigin.SYNTHETIC_HELPER_FOR_ENUM_VALUES
|
||||||
}.apply {
|
}.apply {
|
||||||
@@ -103,9 +161,20 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildEntriesHelperFunction(valuesField: IrField): IrFunction = irClass.addFunction {
|
||||||
|
name = Name.identifier(ENTRIES_HELPER_FUNCTION_NAME)
|
||||||
|
returnType = enumArrayType
|
||||||
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
|
origin = IrDeclarationOrigin.SYNTHETIC_HELPER_FOR_ENUM_VALUES
|
||||||
|
}.apply {
|
||||||
|
body = context.createJvmIrBuilder(symbol).run {
|
||||||
|
irExprBody(irGetField(null, valuesField))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildValuesField(valuesHelperFunction: IrFunction): IrField = irClass.addField {
|
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 = enumArrayType
|
||||||
visibility = DescriptorVisibilities.PRIVATE
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
origin = IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES
|
origin = IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES
|
||||||
isFinal = true
|
isFinal = true
|
||||||
@@ -118,7 +187,53 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class EnumClassDeclarationsTransformer(val valuesField: IrField) : IrElementTransformerVoid() {
|
private fun buildEntriesField(@Suppress("UNUSED_PARAMETER") entriesHelper: IrFunction): IrField = irClass.addField {
|
||||||
|
name = Name.identifier(ENTRIES_FIELD_NAME)
|
||||||
|
type = context.ir.symbols.enumEntries.defaultType
|
||||||
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
|
origin = IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRIES
|
||||||
|
isFinal = true
|
||||||
|
isStatic = true
|
||||||
|
}.apply {
|
||||||
|
initializer = context.createJvmIrBuilder(symbol).run {
|
||||||
|
irExprBody(irBlock {
|
||||||
|
val symbols = this@EnumClassLowering.context.ir.symbols
|
||||||
|
val samClass = context.irBuiltIns.functionN(0)
|
||||||
|
val type = samClass.typeWith(enumArrayType)
|
||||||
|
val sam = type.getClass()!!.getSingleAbstractMethod()!!.symbol
|
||||||
|
/*
|
||||||
|
* Indy to LMF call:
|
||||||
|
* INVOKEDYNAMIC get()Lkotlin/jvm/functions/Function0; [
|
||||||
|
* // handle kind 0x6 : INVOKESTATIC
|
||||||
|
* java/lang/invoke/LambdaMetafactory.metafactory
|
||||||
|
* // arguments:
|
||||||
|
* ()Ljava/lang/Object;,
|
||||||
|
* // handle kind 0x6 : INVOKESTATIC
|
||||||
|
* $entries() [LEnum[,
|
||||||
|
* ()Ljava/util/List;
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
val indyCall = irCall(symbols.indyLambdaMetafactoryIntrinsic, type).apply {
|
||||||
|
putTypeArgument(0, type)
|
||||||
|
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, sam))
|
||||||
|
putValueArgument(1, IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, entriesHelper.symbol, 0, 0))
|
||||||
|
putValueArgument(2, irRawFunctionReferefence(context.irBuiltIns.anyType, sam))
|
||||||
|
putValueArgument(3, irVararg(context.irBuiltIns.anyType, emptyList()))
|
||||||
|
putValueArgument(4, irBoolean(false))
|
||||||
|
}
|
||||||
|
// Bind it to temp var and pass to ctor
|
||||||
|
val supplier = createTmpVariable(indyCall, "supplier")
|
||||||
|
+irCall(symbols.createEnumEntries).apply {
|
||||||
|
putValueArgument(0, irGet(supplier))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class EnumClassDeclarationsTransformer(
|
||||||
|
private val valuesField: IrField, private val entriesField: IrField?
|
||||||
|
) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass): IrStatement =
|
override fun visitClass(declaration: IrClass): IrStatement =
|
||||||
if (declaration.isEnumEntry) super.visitClass(declaration) else declaration
|
if (declaration.isEnumEntry) super.visitClass(declaration) else declaration
|
||||||
|
|
||||||
@@ -165,6 +280,12 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
|||||||
putValueArgument(0, javaClassReference(irClass.defaultType))
|
putValueArgument(0, javaClassReference(irClass.defaultType))
|
||||||
putValueArgument(1, irGet(declaration.valueParameters[0]))
|
putValueArgument(1, irGet(declaration.valueParameters[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IrSyntheticBodyKind.ENUM_ENTRIES -> {
|
||||||
|
// We're ensuring on FE level that this declaration exists only
|
||||||
|
// when the corresponding flag is set up (-> entriesField is never null)
|
||||||
|
irGetField(null, entriesField!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class JvmSymbols(
|
|||||||
private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm"))
|
private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm"))
|
||||||
private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
|
private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
|
||||||
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
|
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
|
||||||
|
private val kotlinEnumPackage: IrPackageFragment = createPackage(FqName("kotlin.enums"))
|
||||||
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
|
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
|
||||||
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
|
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
|
||||||
private val javaLangInvokePackage: IrPackageFragment = createPackage(FqName("java.lang.invoke"))
|
private val javaLangInvokePackage: IrPackageFragment = createPackage(FqName("java.lang.invoke"))
|
||||||
@@ -96,6 +97,7 @@ class JvmSymbols(
|
|||||||
"kotlin" -> kotlinPackage
|
"kotlin" -> kotlinPackage
|
||||||
"kotlin.coroutines" -> kotlinCoroutinesPackage
|
"kotlin.coroutines" -> kotlinCoroutinesPackage
|
||||||
"kotlin.coroutines.jvm.internal" -> kotlinCoroutinesJvmInternalPackage
|
"kotlin.coroutines.jvm.internal" -> kotlinCoroutinesJvmInternalPackage
|
||||||
|
"kotlin.enums" -> kotlinEnumPackage
|
||||||
"kotlin.jvm.internal" -> kotlinJvmInternalPackage
|
"kotlin.jvm.internal" -> kotlinJvmInternalPackage
|
||||||
"kotlin.jvm.functions" -> kotlinJvmFunctionsPackage
|
"kotlin.jvm.functions" -> kotlinJvmFunctionsPackage
|
||||||
"kotlin.jvm" -> kotlinJvmPackage
|
"kotlin.jvm" -> kotlinJvmPackage
|
||||||
@@ -214,6 +216,20 @@ class JvmSymbols(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val enumEntries: IrClassSymbol = createClass(FqName("kotlin.enums.EnumEntries"), ClassKind.INTERFACE) { klass ->
|
||||||
|
// Actually it is E : Enum<E>, but doesn't seem to have any effect yet
|
||||||
|
klass.addTypeParameter("E", irBuiltIns.anyNType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val enumEntriesKt: IrClassSymbol = createClass(FqName("kotlin.enums.EnumEntriesKt")) { klass ->
|
||||||
|
klass.addFunction("enumEntries", enumEntries.defaultType, isStatic = true).apply {
|
||||||
|
addValueParameter("entriesProvider",
|
||||||
|
irBuiltIns.functionN(0).typeWith(irBuiltIns.arrayClass.typeWith(klass.typeParameters.map { it.defaultType })))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val createEnumEntries: IrSimpleFunctionSymbol = enumEntriesKt.functions.single { it.owner.name.asString() == "enumEntries" }
|
||||||
|
|
||||||
override val defaultConstructorMarker: IrClassSymbol =
|
override val defaultConstructorMarker: IrClassSymbol =
|
||||||
createClass(FqName("kotlin.jvm.internal.DefaultConstructorMarker"))
|
createClass(FqName("kotlin.jvm.internal.DefaultConstructorMarker"))
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ interface IrDeclarationOrigin {
|
|||||||
|
|
||||||
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 SYNTHETIC_HELPER_FOR_ENUM_VALUES : IrDeclarationOriginImpl("SYNTHETIC_HELPER_FOR_ENUM_VALUES", isSynthetic = true)
|
||||||
|
object SYNTHETIC_HELPER_FOR_ENUM_ENTRIES : IrDeclarationOriginImpl("SYNTHETIC_HELPER_FOR_ENUM_ENTRIES", 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_ENUM_ENTRIES: IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRIES", isSynthetic = true)
|
||||||
|
object PROPERTY_FOR_ENUM_ENTRIES: IrDeclarationOriginImpl("PROPERTY_FOR_ENUM_ENTRIES", isSynthetic = false)
|
||||||
object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE")
|
object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE")
|
||||||
object FIELD_FOR_CLASS_CONTEXT_RECEIVER : IrDeclarationOriginImpl("FIELD_FOR_CLASS_CONTEXT_RECEIVER", isSynthetic = true)
|
object FIELD_FOR_CLASS_CONTEXT_RECEIVER : IrDeclarationOriginImpl("FIELD_FOR_CLASS_CONTEXT_RECEIVER", isSynthetic = true)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// !LANGUAGE: +EnumEntries
|
||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
// FULL_JDK
|
||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
enum class MyEnum {
|
||||||
|
OK, NOPE
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
fun box(): String {
|
||||||
|
val entries = MyEnum.entries
|
||||||
|
val entry = entries[0]
|
||||||
|
return entry.toString()
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// !LANGUAGE: +EnumEntries
|
||||||
|
|
||||||
|
enum class SimpleEnum {
|
||||||
|
A, B, C
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WithConstructor(val x: String) {
|
||||||
|
A("1"), B("2"), C("3")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WithEntryClass {
|
||||||
|
A {
|
||||||
|
override fun foo() {}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
abstract fun foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
annotation class Ann
|
||||||
|
|
||||||
|
enum class WithAnnotations {
|
||||||
|
@Ann A, @Ann B
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
@java.lang.annotation.Retention(value=RUNTIME)
|
||||||
|
@kotlin.Metadata
|
||||||
|
public annotation class Ann {
|
||||||
|
// source: 'enumEntries.kt'
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class SimpleEnum {
|
||||||
|
// source: 'enumEntries.kt'
|
||||||
|
private synthetic final static field $ENTRIES: kotlin.enums.EnumEntries
|
||||||
|
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 $entries(): SimpleEnum[]
|
||||||
|
private synthetic final static method $values(): SimpleEnum[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method getEntries(): kotlin.enums.EnumEntries
|
||||||
|
public static method valueOf(p0: java.lang.String): SimpleEnum
|
||||||
|
public static method values(): SimpleEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class WithAnnotations {
|
||||||
|
// source: 'enumEntries.kt'
|
||||||
|
private synthetic final static field $ENTRIES: kotlin.enums.EnumEntries
|
||||||
|
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 $entries(): WithAnnotations[]
|
||||||
|
private synthetic final static method $values(): WithAnnotations[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method getEntries(): kotlin.enums.EnumEntries
|
||||||
|
public static method valueOf(p0: java.lang.String): WithAnnotations
|
||||||
|
public static method values(): WithAnnotations[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class WithConstructor {
|
||||||
|
// source: 'enumEntries.kt'
|
||||||
|
private synthetic final static field $ENTRIES: kotlin.enums.EnumEntries
|
||||||
|
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 $entries(): WithConstructor[]
|
||||||
|
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 static @org.jetbrains.annotations.NotNull method getEntries(): kotlin.enums.EnumEntries
|
||||||
|
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: 'enumEntries.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: 'enumEntries.kt'
|
||||||
|
private synthetic final static field $ENTRIES: kotlin.enums.EnumEntries
|
||||||
|
private synthetic final static field $VALUES: WithEntryClass[]
|
||||||
|
public final enum static field A: WithEntryClass
|
||||||
|
final inner class WithEntryClass$A
|
||||||
|
private synthetic final static method $entries(): WithEntryClass[]
|
||||||
|
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 final static @org.jetbrains.annotations.NotNull method getEntries(): kotlin.enums.EnumEntries
|
||||||
|
public static method valueOf(p0: java.lang.String): WithEntryClass
|
||||||
|
public static method values(): WithEntryClass[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
// !LANGUAGE: +EnumEntries
|
||||||
|
|
||||||
|
enum class MyEnum {
|
||||||
|
E
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 INVOKEDYNAMIC
|
||||||
|
// 1 kotlin.enums.EnumEntries<MyEnum> getEntries\(\)
|
||||||
|
// 1 private final static synthetic Lkotlin/enums/EnumEntries; \$ENTRIES
|
||||||
|
// 1 public final static getEntries\(\)Lkotlin/enums/EnumEntries;
|
||||||
|
// 0 [^\$]entries
|
||||||
+6
@@ -16281,6 +16281,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumConstructorParameterClashWithDefaults.kt");
|
runTest("compiler/testData/codegen/box/enum/enumConstructorParameterClashWithDefaults.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntries.kt")
|
||||||
|
public void testEnumEntries() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntries.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumEntryMembers.kt")
|
@TestMetadata("enumEntryMembers.kt")
|
||||||
public void testEnumEntryMembers() throws Exception {
|
public void testEnumEntryMembers() throws Exception {
|
||||||
|
|||||||
+6
@@ -109,6 +109,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
|||||||
runTest("compiler/testData/codegen/bytecodeListing/enum.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/enum.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntries.kt")
|
||||||
|
public void testEnumEntries() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeListing/enumEntries.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("extension.kt")
|
@TestMetadata("extension.kt")
|
||||||
public void testExtension() throws Exception {
|
public void testExtension() throws Exception {
|
||||||
|
|||||||
+6
@@ -2194,6 +2194,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt");
|
runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntries.kt")
|
||||||
|
public void testEnumEntries() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/enum/enumEntries.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt18731.kt")
|
@TestMetadata("kt18731.kt")
|
||||||
public void testKt18731() throws Exception {
|
public void testKt18731() throws Exception {
|
||||||
|
|||||||
Generated
+6
@@ -136,6 +136,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest {
|
|||||||
runTest("compiler/testData/ir/irText/classes/enumClassModality.kt");
|
runTest("compiler/testData/ir/irText/classes/enumClassModality.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntries.kt")
|
||||||
|
public void testEnumEntries() throws Exception {
|
||||||
|
runTest("compiler/testData/ir/irText/classes/enumEntries.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumWithMultipleCtors.kt")
|
@TestMetadata("enumWithMultipleCtors.kt")
|
||||||
public void testEnumWithMultipleCtors() throws Exception {
|
public void testEnumWithMultipleCtors() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user