[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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntries.kt")
|
||||
public void testEnumEntries() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/enumEntries.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntryMembers.kt")
|
||||
public void testEnumEntryMembers() throws Exception {
|
||||
|
||||
+6
@@ -2194,6 +2194,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
||||
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
|
||||
@TestMetadata("kt18731.kt")
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -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.JvmLoweredDeclarationOrigin
|
||||
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.javaClassReference
|
||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
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.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.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
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.util.*
|
||||
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 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) {
|
||||
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 loweredEnumConstructorParameters = hashMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||
private val enumEntryOrdinals = TObjectIntHashMap<IrEnumEntry>()
|
||||
private val declarationToEnumEntry = mutableMapOf<IrDeclaration, IrEnumEntry>()
|
||||
private val enumArrayType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType) // Enum[]
|
||||
|
||||
fun run() {
|
||||
// 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()
|
||||
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
|
||||
irClass.transformChildrenVoid(EnumClassDeclarationsTransformer(valuesField))
|
||||
irClass.transformChildrenVoid(EnumClassDeclarationsTransformer(valuesField, entriesField))
|
||||
|
||||
// Add synthetic arguments to enum constructor calls and remap enum constructor parameters
|
||||
irClass.transformChildrenVoid(EnumClassCallTransformer())
|
||||
@@ -85,12 +143,12 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
||||
private fun buildEnumEntryField(enumEntry: IrEnumEntry): IrField =
|
||||
context.cachedDeclarations.getFieldForEnumEntry(enumEntry).apply {
|
||||
initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!.expression.patchDeclarationParents(this))
|
||||
annotations += enumEntry.annotations
|
||||
annotations = annotations + enumEntry.annotations
|
||||
}
|
||||
|
||||
private fun buildValuesHelperFunction(): IrFunction = irClass.addFunction {
|
||||
name = Name.identifier(VALUES_HELPER_FUNCTION_NAME)
|
||||
returnType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
||||
returnType = enumArrayType
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
origin = IrDeclarationOrigin.SYNTHETIC_HELPER_FOR_ENUM_VALUES
|
||||
}.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 {
|
||||
name = Name.identifier(ImplementationBodyCodegen.ENUM_VALUES_FIELD_NAME)
|
||||
type = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
||||
type = enumArrayType
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
origin = IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES
|
||||
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 =
|
||||
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(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 kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
|
||||
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 javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
|
||||
private val javaLangInvokePackage: IrPackageFragment = createPackage(FqName("java.lang.invoke"))
|
||||
@@ -96,6 +97,7 @@ class JvmSymbols(
|
||||
"kotlin" -> kotlinPackage
|
||||
"kotlin.coroutines" -> kotlinCoroutinesPackage
|
||||
"kotlin.coroutines.jvm.internal" -> kotlinCoroutinesJvmInternalPackage
|
||||
"kotlin.enums" -> kotlinEnumPackage
|
||||
"kotlin.jvm.internal" -> kotlinJvmInternalPackage
|
||||
"kotlin.jvm.functions" -> kotlinJvmFunctionsPackage
|
||||
"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 =
|
||||
createClass(FqName("kotlin.jvm.internal.DefaultConstructorMarker"))
|
||||
|
||||
|
||||
@@ -60,7 +60,10 @@ interface IrDeclarationOrigin {
|
||||
|
||||
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_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_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_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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntries.kt")
|
||||
public void testEnumEntries() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/enumEntries.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntryMembers.kt")
|
||||
public void testEnumEntryMembers() throws Exception {
|
||||
|
||||
+6
@@ -109,6 +109,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
runTest("compiler/testData/codegen/bytecodeListing/enum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntries.kt")
|
||||
public void testEnumEntries() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/enumEntries.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extension.kt")
|
||||
public void testExtension() throws Exception {
|
||||
|
||||
+6
@@ -2194,6 +2194,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
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
|
||||
@TestMetadata("kt18731.kt")
|
||||
public void testKt18731() throws Exception {
|
||||
|
||||
Generated
+6
@@ -136,6 +136,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest {
|
||||
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
|
||||
@TestMetadata("enumWithMultipleCtors.kt")
|
||||
public void testEnumWithMultipleCtors() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user