From 895a8ff14920d02a77476b3114bfe5e3ca234fba Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Thu, 18 Aug 2022 17:23:55 +0200 Subject: [PATCH] [K/N] Basic support of Enum.entries for Native No forward compatibility yet, with old klib IR linker will fail. ^KT-53324 --- .../FirBlackBoxCodegenTestGenerated.java | 12 ++ .../testData/codegen/box/enum/enumEntries.kt | 2 +- .../box/enum/enumEntriesMultimodule.kt | 2 +- .../enumEntriesMultimoduleMultipleMappings.kt | 2 +- ...leMultipleMappingsForMultipleClassfiles.kt | 2 +- .../enum/enumEntriesMultimoduleNoMappings.kt | 18 +++ .../box/enum/enumEntriesNameClashes.kt | 19 +++ .../IrBlackBoxCodegenTestGenerated.java | 12 ++ .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 9 +- .../backend/konan/lower/EnumClassLowering.kt | 115 +++++++++++++----- .../backend.native/tests/build.gradle | 1 + .../tests/interop/basics/enums.kt | 14 +++ .../stdlib/src/kotlin/enums/EnumEntries.kt | 13 +- .../NativeCodegenBoxTestGenerated.java | 18 +++ 14 files changed, 199 insertions(+), 40 deletions(-) create mode 100644 compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt create mode 100644 compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 853d1f6d9d1..f1d2d523187 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -16323,6 +16323,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt"); } + @Test + @TestMetadata("enumEntriesMultimoduleNoMappings.kt") + public void testEnumEntriesMultimoduleNoMappings() throws Exception { + runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt"); + } + + @Test + @TestMetadata("enumEntriesNameClashes.kt") + public void testEnumEntriesNameClashes() throws Exception { + runTest("compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt"); + } + @Test @TestMetadata("enumEntryMembers.kt") public void testEnumEntryMembers() throws Exception { diff --git a/compiler/testData/codegen/box/enum/enumEntries.kt b/compiler/testData/codegen/box/enum/enumEntries.kt index 3e9c8ef6d30..192a3e99bab 100644 --- a/compiler/testData/codegen/box/enum/enumEntries.kt +++ b/compiler/testData/codegen/box/enum/enumEntries.kt @@ -1,6 +1,6 @@ // !LANGUAGE: +EnumEntries // TARGET_BACKEND: JVM_IR -// FULL_JDK +// TARGET_BACKEND: NATIVE // WITH_STDLIB enum class MyEnum { diff --git a/compiler/testData/codegen/box/enum/enumEntriesMultimodule.kt b/compiler/testData/codegen/box/enum/enumEntriesMultimodule.kt index 789f23a4c65..63fddc3ca9c 100644 --- a/compiler/testData/codegen/box/enum/enumEntriesMultimodule.kt +++ b/compiler/testData/codegen/box/enum/enumEntriesMultimodule.kt @@ -1,5 +1,5 @@ // TARGET_BACKEND: JVM_IR -// FULL_JDK +// AFTER KT-53649 - TARGET_BACKEND: NATIVE // WITH_STDLIB // MODULE: lib diff --git a/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappings.kt b/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappings.kt index a540e011727..bea4ae409df 100644 --- a/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappings.kt +++ b/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappings.kt @@ -1,5 +1,5 @@ // TARGET_BACKEND: JVM_IR -// FULL_JDK +// AFTER KT-53649 - TARGET_BACKEND: NATIVE // WITH_STDLIB // MODULE: lib diff --git a/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt b/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt index f8a7eab35b3..aeca12aff98 100644 --- a/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt +++ b/compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt @@ -1,5 +1,5 @@ // TARGET_BACKEND: JVM_IR -// FULL_JDK +// AFTER KT-53649 - TARGET_BACKEND: NATIVE // WITH_STDLIB // MODULE: lib diff --git a/compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt b/compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt new file mode 100644 index 00000000000..68b2a55b26f --- /dev/null +++ b/compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM_IR +// TARGET_BACKEND: NATIVE +// WITH_STDLIB + +// MODULE: lib +// !LANGUAGE: +EnumEntries +// FILE: MyEnum.kt +enum class MyEnum { + Nope, OK +} + +// MODULE: caller(lib) +// !LANGUAGE: +EnumEntries +// FILE: Box.kt +@OptIn(ExperimentalStdlibApi::class) +fun box(): String { + return MyEnum.entries[1].toString() +} diff --git a/compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt b/compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt new file mode 100644 index 00000000000..ba3b28cf7ad --- /dev/null +++ b/compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt @@ -0,0 +1,19 @@ +// !LANGUAGE: +EnumEntries +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: NATIVE +// WITH_STDLIB + +enum class EnumWithClash { + values, + entries, + valueOf; +} + +@OptIn(ExperimentalStdlibApi::class) +fun box(): String { + val ref = EnumWithClash::entries + if (ref().toString() != "[values, entries, valueOf]") return "FAIL 1" + if (EnumWithClash.entries.toString() != "entries") return "FAIL 2" + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index b1b9d8ffe93..68a2784ee95 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -16323,6 +16323,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt"); } + @Test + @TestMetadata("enumEntriesMultimoduleNoMappings.kt") + public void testEnumEntriesMultimoduleNoMappings() throws Exception { + runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt"); + } + + @Test + @TestMetadata("enumEntriesNameClashes.kt") + public void testEnumEntriesNameClashes() throws Exception { + runTest("compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt"); + } + @Test @TestMetadata("enumEntryMembers.kt") public void testEnumEntryMembers() throws Exception { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index dfe99fee5ef..10e1d6aa7e5 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -1,6 +1,6 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. + * 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. */ package org.jetbrains.kotlin.backend.konan.ir @@ -303,6 +303,11 @@ internal class KonanSymbols( val valueOfForEnum = internalFunction("valueOfForEnum") + val createEnumEntries = irBuiltIns.findFunctions(Name.identifier("enumEntries"), "kotlin", "enums") + .single { it.descriptor.valueParameters.singleOrNull()?.type?.constructor?.declarationDescriptor == array.descriptor } + + val enumEntriesInterface = irBuiltIns.findClass(Name.identifier("EnumEntries"), "kotlin", "enums")!! + val createUninitializedInstance = internalFunction("createUninitializedInstance") val initInstance = internalFunction("initInstance") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index 54233dc0869..d6f2bcdfc6a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -1,6 +1,6 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. + * 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. */ package org.jetbrains.kotlin.backend.konan.lower @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.MemoryModel import org.jetbrains.kotlin.backend.konan.NativeMapping import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName +import org.jetbrains.kotlin.backend.konan.ir.KonanNameConventions import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType @@ -51,6 +52,7 @@ internal class EnumsSupport( private val enumValueGetters = mapping.enumValueGetters private val enumEntriesMaps = mapping.enumEntriesMaps private val array = symbols.array + private val enumEntries = symbols.enumEntriesInterface private val genericValueOfSymbol = symbols.valueOfForEnum private val genericValuesSymbol = symbols.valuesForEnum @@ -75,7 +77,7 @@ internal class EnumsSupport( startOffset = enumClass.startOffset endOffset = enumClass.endOffset origin = DECLARATION_ORIGIN_ENUM - name = "OBJECT".synthesizedName + name = implObjectName kind = ClassKind.OBJECT }.apply { superTypes = listOf(irBuiltIns.anyType) @@ -85,11 +87,20 @@ internal class EnumsSupport( startOffset = enumClass.startOffset endOffset = enumClass.endOffset origin = DECLARATION_ORIGIN_ENUM - name = "VALUES".synthesizedName + name = valuesFieldName type = array.typeWith(enumClass.defaultType) visibility = DescriptorVisibilities.PRIVATE isFinal = true }) + addChild(irFactory.buildField { + startOffset = enumClass.startOffset + endOffset = enumClass.endOffset + origin = DECLARATION_ORIGIN_ENUM + name = entriesFieldName + type = enumEntries.typeWith(enumClass.defaultType) + visibility = DescriptorVisibilities.PRIVATE + isFinal = true + }) } } } @@ -115,7 +126,8 @@ internal class EnumsSupport( } } - fun getValuesField(implObject: IrClass) = implObject.fields.single() + fun getValuesField(implObject: IrClass) = implObject.fields.single { it.name == valuesFieldName } + fun getEntriesField(implObject: IrClass) = implObject.fields.single { it.name == entriesFieldName } fun IrBuilderWithScope.irGetValuesField(enumClass: IrClass): IrExpression { val implObject = getImplObject(enumClass) @@ -123,16 +135,28 @@ internal class EnumsSupport( return irGetField(irGetObject(implObject.symbol), valuesField) } - fun IrBuilderWithScope.irEnumValues(enumClass: IrClass) = + fun IrBuilderWithScope.irEnumValues(enumClass: IrClass) : IrExpression = irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply { putValueArgument(0, irGetValuesField(enumClass)) } - fun IrBuilderWithScope.irEnumValueOf(enumClass: IrClass, value: IrExpression) = + fun IrBuilderWithScope.irEnumValueOf(enumClass: IrClass, value: IrExpression) : IrExpression = irCall(genericValueOfSymbol, listOf(enumClass.defaultType)).apply { putValueArgument(0, value) putValueArgument(1, irGetValuesField(enumClass)) } + + fun IrBuilderWithScope.irEnumEntries(enumClass: IrClass) : IrExpression { + val implObject = getImplObject(enumClass) + val entriesField = getEntriesField(implObject) + return irGetField(irGetObject(implObject.symbol), entriesField) + } + + companion object { + val valuesFieldName = "VALUES".synthesizedName + val entriesFieldName = "ENTRIES".synthesizedName + val implObjectName = "OBJECT".synthesizedName + } } internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM") @@ -201,8 +225,9 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { private val enumsSupport = context.enumsSupport private val symbols = context.ir.symbols private val createUninitializedInstance = symbols.createUninitializedInstance + private val createEnumEntries = symbols.createEnumEntries private val initInstance = symbols.initInstance - private val arrayGet = symbols.arrayGet[symbols.array]!! + private val arrayGet = symbols.array.owner.functions.single { it.name == KonanNameConventions.getWithoutBoundCheck }.symbol private val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first() override fun lower(irFile: IrFile) { @@ -219,6 +244,7 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { private inner class EnumClassTransformer(val irClass: IrClass) { private val implObject = enumsSupport.getImplObject(irClass) private val valuesField = enumsSupport.getValuesField(implObject) + private val entriesField = enumsSupport.getEntriesField(implObject) private val enumEntriesMap = enumsSupport.enumEntriesMap(irClass) fun run() { @@ -237,28 +263,27 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { declaration.correspondingClass = null listOfNotNull(correspondingClass) } - - is IrFunction -> { - val body = declaration.body - if (body is IrSyntheticBody) { - declaration.body = when (body.kind) { - IrSyntheticBodyKind.ENUM_VALUEOF -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) { - +irReturn(with(enumsSupport) { irEnumValueOf(irClass, irGet(declaration.valueParameters[0])) }) - } - - IrSyntheticBodyKind.ENUM_VALUES -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) { - +irReturn(with(enumsSupport) { irEnumValues(irClass) }) - } - - IrSyntheticBodyKind.ENUM_ENTRIES -> TODO("KT-48872 is not yet supported") - } - } - null - } - else -> null } } + irClass.simpleFunctions().forEach { declaration -> + val body = declaration.body + if (body is IrSyntheticBody) { + declaration.body = when (body.kind) { + IrSyntheticBodyKind.ENUM_VALUEOF -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) { + +irReturn(with(enumsSupport) { irEnumValueOf(irClass, irGet(declaration.valueParameters[0])) }) + } + + IrSyntheticBodyKind.ENUM_VALUES -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) { + +irReturn(with(enumsSupport) { irEnumValues(irClass) }) + } + + IrSyntheticBodyKind.ENUM_ENTRIES -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) { + +irReturn(with(enumsSupport) { irEnumEntries(irClass) }) + } + } + } + } return enumEntries } @@ -297,6 +322,16 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { statements += buildValuesFieldInitializer(enumEntries) // Split allocation and constructors calling because enum entries can reference one another. statements += callEnumEntriesConstructors(enumEntries) + statements += buildEntriesFieldInitializer() + + // Needed for legacy MM targets that do not support threads. + if (this@EnumClassLowering.context.memoryModel != MemoryModel.EXPERIMENTAL) { + statements += irBuilder.irBlock { + irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(valuesField.type)).apply { + extensionReceiver = irGet(implObject.thisReceiver!!) + } + } + } irClass.companionObject()?.let { statements += irBuilder.irGetObject(it.symbol) } } @@ -331,6 +366,26 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { irSetField(irGet(implObject.thisReceiver!!), valuesField, irValuesInitializer) } + private fun buildEntriesFieldInitializer() = irBuilder.irBlock { + val irValuesArray = irTemporary(irGetField(irGet(implObject.thisReceiver!!), valuesField)) + val irEntriesArray = this@EnumClassLowering.context.createArrayOfExpression( + startOffset, endOffset, + irClass.defaultType, + enumEntriesMap.values + .sortedBy { it.ordinal } + .map { + irCall(arrayGet, irClass.defaultType).apply { + dispatchReceiver = irGet(irValuesArray) + putValueArgument(0, irInt(it.getterId)) + } + } + ) + val irEntriesInitializer = irCall(createEnumEntries, listOf(irClass.defaultType)).apply { + putValueArgument(0, irEntriesArray) + } + +irSetField(irGet(implObject.thisReceiver!!), entriesField, irEntriesInitializer) + } + private fun callEnumEntriesConstructors(enumEntries: List) = irBuilder.irBlock { val receiver = implObject.thisReceiver!! val instances = irTemporary(irGetField(irGet(receiver), valuesField)) @@ -354,12 +409,6 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass { else -> error("Unexpected initializer: $initializer") } } - // Needed for legacy MM targets that do not support threads. - if (this@EnumClassLowering.context.memoryModel != MemoryModel.EXPERIMENTAL) { - +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(valuesField.type)).apply { - extensionReceiver = irGet(receiver) - } - } } } } diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 338105472c2..200c0e61b6d 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -4737,6 +4737,7 @@ interopTest("interop_union") { interopTest("interop_enums") { disabled = (project.testTarget == 'wasm32') // No interop for wasm yet. interop = 'cenums' + flags = ['-XXLanguage:+EnumEntries'] source = "interop/basics/enums.kt" } diff --git a/kotlin-native/backend.native/tests/interop/basics/enums.kt b/kotlin-native/backend.native/tests/interop/basics/enums.kt index 56eedaa0d01..98e925f272b 100644 --- a/kotlin-native/backend.native/tests/interop/basics/enums.kt +++ b/kotlin-native/backend.native/tests/interop/basics/enums.kt @@ -1,7 +1,13 @@ +/* + * 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. + */ + import cenums.* import kotlinx.cinterop.* import kotlin.test.* +@OptIn(kotlin.ExperimentalStdlibApi::class) fun main() { memScoped { val e = alloc() @@ -12,4 +18,12 @@ fun main() { e.value = TODO() } } + val values = E.values() + assertEquals(values[0], E.A) + assertEquals(values[1], E.B) + assertEquals(values[2], E.C) + val entries = E.entries + assertEquals(entries[0], E.A) + assertEquals(entries[1], E.B) + assertEquals(entries[2], E.C) } \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/enums/EnumEntries.kt b/libraries/stdlib/src/kotlin/enums/EnumEntries.kt index d13534a4f52..9a627f6d480 100644 --- a/libraries/stdlib/src/kotlin/enums/EnumEntries.kt +++ b/libraries/stdlib/src/kotlin/enums/EnumEntries.kt @@ -27,7 +27,18 @@ internal fun > enumEntries(entriesProvider: () -> Array): EnumEnt @PublishedApi @ExperimentalStdlibApi @SinceKotlin("1.8") // Used by Native/JS compilers and Java serialization -internal fun > enumEntries(entries: Array): EnumEntries = EnumEntriesList { entries } +internal fun > enumEntries(entries: Array): EnumEntries = EnumEntriesList { entries }.also { + /* + * Here we are enforcing initialization of _entries property. + * It is required because of two reasons. + * 1. In old Native mm the object will be frozen after creation, so it must be immutable + * 2. Native doesn't support @Volatile for now, so this initialization is not generally safe, if + * done after object is published. + * + * This is very implementation-dependent hack, and it should be removed when/if both reasons above are gone. + */ + it.size +} /* * For enum class E, this class is instantiated in the following manner (NB it's pseudocode that does not diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index cdf4d215493..ad9b0d57829 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -13513,6 +13513,24 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest 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("enumEntriesMultimoduleNoMappings.kt") + public void testEnumEntriesMultimoduleNoMappings() throws Exception { + runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleNoMappings.kt"); + } + + @Test + @TestMetadata("enumEntriesNameClashes.kt") + public void testEnumEntriesNameClashes() throws Exception { + runTest("compiler/testData/codegen/box/enum/enumEntriesNameClashes.kt"); + } + @Test @TestMetadata("enumEntryMembers.kt") public void testEnumEntryMembers() throws Exception {