[K/N] Basic support of Enum.entries for Native
No forward compatibility yet, with old klib IR linker will fail. ^KT-53324
This commit is contained in:
+12
@@ -16323,6 +16323,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt");
|
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
|
@Test
|
||||||
@TestMetadata("enumEntryMembers.kt")
|
@TestMetadata("enumEntryMembers.kt")
|
||||||
public void testEnumEntryMembers() throws Exception {
|
public void testEnumEntryMembers() throws Exception {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// !LANGUAGE: +EnumEntries
|
// !LANGUAGE: +EnumEntries
|
||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// FULL_JDK
|
// TARGET_BACKEND: NATIVE
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|
||||||
enum class MyEnum {
|
enum class MyEnum {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// FULL_JDK
|
// AFTER KT-53649 - TARGET_BACKEND: NATIVE
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// FULL_JDK
|
// AFTER KT-53649 - TARGET_BACKEND: NATIVE
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// FULL_JDK
|
// AFTER KT-53649 - TARGET_BACKEND: NATIVE
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
+12
@@ -16323,6 +16323,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesMultimoduleMultipleMappingsForMultipleClassfiles.kt");
|
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
|
@Test
|
||||||
@TestMetadata("enumEntryMembers.kt")
|
@TestMetadata("enumEntryMembers.kt")
|
||||||
public void testEnumEntryMembers() throws Exception {
|
public void testEnumEntryMembers() throws Exception {
|
||||||
|
|||||||
+7
-2
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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
|
package org.jetbrains.kotlin.backend.konan.ir
|
||||||
@@ -303,6 +303,11 @@ internal class KonanSymbols(
|
|||||||
|
|
||||||
val valueOfForEnum = internalFunction("valueOfForEnum")
|
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 createUninitializedInstance = internalFunction("createUninitializedInstance")
|
||||||
|
|
||||||
val initInstance = internalFunction("initInstance")
|
val initInstance = internalFunction("initInstance")
|
||||||
|
|||||||
+82
-33
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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
|
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.MemoryModel
|
||||||
import org.jetbrains.kotlin.backend.konan.NativeMapping
|
import org.jetbrains.kotlin.backend.konan.NativeMapping
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
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.ir.KonanSymbols
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
|
import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
|
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
|
||||||
@@ -51,6 +52,7 @@ internal class EnumsSupport(
|
|||||||
private val enumValueGetters = mapping.enumValueGetters
|
private val enumValueGetters = mapping.enumValueGetters
|
||||||
private val enumEntriesMaps = mapping.enumEntriesMaps
|
private val enumEntriesMaps = mapping.enumEntriesMaps
|
||||||
private val array = symbols.array
|
private val array = symbols.array
|
||||||
|
private val enumEntries = symbols.enumEntriesInterface
|
||||||
private val genericValueOfSymbol = symbols.valueOfForEnum
|
private val genericValueOfSymbol = symbols.valueOfForEnum
|
||||||
private val genericValuesSymbol = symbols.valuesForEnum
|
private val genericValuesSymbol = symbols.valuesForEnum
|
||||||
|
|
||||||
@@ -75,7 +77,7 @@ internal class EnumsSupport(
|
|||||||
startOffset = enumClass.startOffset
|
startOffset = enumClass.startOffset
|
||||||
endOffset = enumClass.endOffset
|
endOffset = enumClass.endOffset
|
||||||
origin = DECLARATION_ORIGIN_ENUM
|
origin = DECLARATION_ORIGIN_ENUM
|
||||||
name = "OBJECT".synthesizedName
|
name = implObjectName
|
||||||
kind = ClassKind.OBJECT
|
kind = ClassKind.OBJECT
|
||||||
}.apply {
|
}.apply {
|
||||||
superTypes = listOf(irBuiltIns.anyType)
|
superTypes = listOf(irBuiltIns.anyType)
|
||||||
@@ -85,11 +87,20 @@ internal class EnumsSupport(
|
|||||||
startOffset = enumClass.startOffset
|
startOffset = enumClass.startOffset
|
||||||
endOffset = enumClass.endOffset
|
endOffset = enumClass.endOffset
|
||||||
origin = DECLARATION_ORIGIN_ENUM
|
origin = DECLARATION_ORIGIN_ENUM
|
||||||
name = "VALUES".synthesizedName
|
name = valuesFieldName
|
||||||
type = array.typeWith(enumClass.defaultType)
|
type = array.typeWith(enumClass.defaultType)
|
||||||
visibility = DescriptorVisibilities.PRIVATE
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
isFinal = true
|
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 {
|
fun IrBuilderWithScope.irGetValuesField(enumClass: IrClass): IrExpression {
|
||||||
val implObject = getImplObject(enumClass)
|
val implObject = getImplObject(enumClass)
|
||||||
@@ -123,16 +135,28 @@ internal class EnumsSupport(
|
|||||||
return irGetField(irGetObject(implObject.symbol), valuesField)
|
return irGetField(irGetObject(implObject.symbol), valuesField)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrBuilderWithScope.irEnumValues(enumClass: IrClass) =
|
fun IrBuilderWithScope.irEnumValues(enumClass: IrClass) : IrExpression =
|
||||||
irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply {
|
irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply {
|
||||||
putValueArgument(0, irGetValuesField(enumClass))
|
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 {
|
irCall(genericValueOfSymbol, listOf(enumClass.defaultType)).apply {
|
||||||
putValueArgument(0, value)
|
putValueArgument(0, value)
|
||||||
putValueArgument(1, irGetValuesField(enumClass))
|
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")
|
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 enumsSupport = context.enumsSupport
|
||||||
private val symbols = context.ir.symbols
|
private val symbols = context.ir.symbols
|
||||||
private val createUninitializedInstance = symbols.createUninitializedInstance
|
private val createUninitializedInstance = symbols.createUninitializedInstance
|
||||||
|
private val createEnumEntries = symbols.createEnumEntries
|
||||||
private val initInstance = symbols.initInstance
|
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()
|
private val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
@@ -219,6 +244,7 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
|||||||
private inner class EnumClassTransformer(val irClass: IrClass) {
|
private inner class EnumClassTransformer(val irClass: IrClass) {
|
||||||
private val implObject = enumsSupport.getImplObject(irClass)
|
private val implObject = enumsSupport.getImplObject(irClass)
|
||||||
private val valuesField = enumsSupport.getValuesField(implObject)
|
private val valuesField = enumsSupport.getValuesField(implObject)
|
||||||
|
private val entriesField = enumsSupport.getEntriesField(implObject)
|
||||||
private val enumEntriesMap = enumsSupport.enumEntriesMap(irClass)
|
private val enumEntriesMap = enumsSupport.enumEntriesMap(irClass)
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
@@ -237,28 +263,27 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
|||||||
declaration.correspondingClass = null
|
declaration.correspondingClass = null
|
||||||
listOfNotNull(correspondingClass)
|
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
|
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
|
return enumEntries
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +322,16 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
|||||||
statements += buildValuesFieldInitializer(enumEntries)
|
statements += buildValuesFieldInitializer(enumEntries)
|
||||||
// Split allocation and constructors calling because enum entries can reference one another.
|
// Split allocation and constructors calling because enum entries can reference one another.
|
||||||
statements += callEnumEntriesConstructors(enumEntries)
|
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) }
|
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)
|
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<IrEnumEntry>) = irBuilder.irBlock {
|
private fun callEnumEntriesConstructors(enumEntries: List<IrEnumEntry>) = irBuilder.irBlock {
|
||||||
val receiver = implObject.thisReceiver!!
|
val receiver = implObject.thisReceiver!!
|
||||||
val instances = irTemporary(irGetField(irGet(receiver), valuesField))
|
val instances = irTemporary(irGetField(irGet(receiver), valuesField))
|
||||||
@@ -354,12 +409,6 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
|||||||
else -> error("Unexpected initializer: $initializer")
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4737,6 +4737,7 @@ interopTest("interop_union") {
|
|||||||
interopTest("interop_enums") {
|
interopTest("interop_enums") {
|
||||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||||
interop = 'cenums'
|
interop = 'cenums'
|
||||||
|
flags = ['-XXLanguage:+EnumEntries']
|
||||||
source = "interop/basics/enums.kt"
|
source = "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 cenums.*
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
|
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||||
fun main() {
|
fun main() {
|
||||||
memScoped {
|
memScoped {
|
||||||
val e = alloc<E.Var>()
|
val e = alloc<E.Var>()
|
||||||
@@ -12,4 +18,12 @@ fun main() {
|
|||||||
e.value = TODO()
|
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)
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,18 @@ internal fun <E : Enum<E>> enumEntries(entriesProvider: () -> Array<E>): EnumEnt
|
|||||||
@PublishedApi
|
@PublishedApi
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@SinceKotlin("1.8") // Used by Native/JS compilers and Java serialization
|
@SinceKotlin("1.8") // Used by Native/JS compilers and Java serialization
|
||||||
internal fun <E : Enum<E>> enumEntries(entries: Array<E>): EnumEntries<E> = EnumEntriesList { entries }
|
internal fun <E : Enum<E>> enumEntries(entries: Array<E>): EnumEntries<E> = 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
|
* For enum class E, this class is instantiated in the following manner (NB it's pseudocode that does not
|
||||||
|
|||||||
+18
@@ -13513,6 +13513,24 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
|
|||||||
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
|
||||||
|
@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
|
@Test
|
||||||
@TestMetadata("enumEntryMembers.kt")
|
@TestMetadata("enumEntryMembers.kt")
|
||||||
public void testEnumEntryMembers() throws Exception {
|
public void testEnumEntryMembers() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user