JVM: support enumEntries intrinsic for Java & old Kotlin enums
#KT-59710 Fixed
This commit is contained in:
committed by
Space Team
parent
874d1c514a
commit
971b4e63e7
@@ -24,6 +24,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
|||||||
import org.jetbrains.org.objectweb.asm.Type.INT_TYPE
|
import org.jetbrains.org.objectweb.asm.Type.INT_TYPE
|
||||||
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
|
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||||
|
|
||||||
class PsiInlineIntrinsicsSupport(
|
class PsiInlineIntrinsicsSupport(
|
||||||
override val state: GenerationState,
|
override val state: GenerationState,
|
||||||
@@ -72,6 +73,10 @@ class PsiInlineIntrinsicsSupport(
|
|||||||
|
|
||||||
override fun toKotlinType(type: KotlinType): KotlinType = type
|
override fun toKotlinType(type: KotlinType): KotlinType = type
|
||||||
|
|
||||||
|
override fun generateExternalEntriesForEnumTypeIfNeeded(type: KotlinType): FieldInsnNode? {
|
||||||
|
error("Not supported in the old JVM backend")
|
||||||
|
}
|
||||||
|
|
||||||
override fun reportSuspendTypeUnsupported() {
|
override fun reportSuspendTypeUnsupported() {
|
||||||
state.diagnostics.report(TYPEOF_SUSPEND_TYPE.on(reportErrorsOn))
|
state.diagnostics.report(TYPEOF_SUSPEND_TYPE.on(reportErrorsOn))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
|||||||
|
|
||||||
fun toKotlinType(type: KT): KotlinType
|
fun toKotlinType(type: KT): KotlinType
|
||||||
|
|
||||||
|
fun generateExternalEntriesForEnumTypeIfNeeded(type: KT): FieldInsnNode?
|
||||||
|
|
||||||
fun reportSuspendTypeUnsupported()
|
fun reportSuspendTypeUnsupported()
|
||||||
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
|
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
|
||||||
|
|
||||||
@@ -187,7 +189,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
|||||||
OperationKind.SAFE_AS -> processAs(insn, instructions, type, asmType, safe = true)
|
OperationKind.SAFE_AS -> processAs(insn, instructions, type, asmType, safe = true)
|
||||||
OperationKind.IS -> processIs(insn, instructions, type, asmType)
|
OperationKind.IS -> processIs(insn, instructions, type, asmType)
|
||||||
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
||||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
|
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, type, asmType)
|
||||||
OperationKind.TYPE_OF -> processTypeOf(insn, instructions, type)
|
OperationKind.TYPE_OF -> processTypeOf(insn, instructions, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +344,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processSpecialEnumFunction(insn: MethodInsnNode, instructions: InsnList, parameter: Type): Boolean {
|
private fun processSpecialEnumFunction(insn: MethodInsnNode, instructions: InsnList, type: KT, parameter: Type): Boolean {
|
||||||
val next1 = insn.next ?: return false
|
val next1 = insn.next ?: return false
|
||||||
val next2 = next1.next ?: return false
|
val next2 = next1.next ?: return false
|
||||||
if (next1.opcode == Opcodes.ACONST_NULL && next2.opcode == Opcodes.ALOAD) {
|
if (next1.opcode == Opcodes.ACONST_NULL && next2.opcode == Opcodes.ALOAD) {
|
||||||
@@ -362,12 +364,17 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
|||||||
} else if (next1.opcode == Opcodes.ACONST_NULL && next2.opcode == Opcodes.CHECKCAST) {
|
} else if (next1.opcode == Opcodes.ACONST_NULL && next2.opcode == Opcodes.CHECKCAST) {
|
||||||
instructions.remove(next1)
|
instructions.remove(next1)
|
||||||
instructions.remove(next2)
|
instructions.remove(next2)
|
||||||
// TODO: support enumEntries for Java enums.
|
|
||||||
instructions.insert(
|
val getField = intrinsicsSupport.generateExternalEntriesForEnumTypeIfNeeded(type)
|
||||||
insn, MethodInsnNode(
|
if (getField != null) {
|
||||||
Opcodes.INVOKESTATIC, parameter.internalName, "getEntries", Type.getMethodDescriptor(AsmTypes.ENUM_ENTRIES), false
|
instructions.insert(insn, getField)
|
||||||
|
} else {
|
||||||
|
instructions.insert(
|
||||||
|
insn, MethodInsnNode(
|
||||||
|
Opcodes.INVOKESTATIC, parameter.internalName, "getEntries", Type.getMethodDescriptor(AsmTypes.ENUM_ENTRIES), false
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
@@ -16693,6 +16693,18 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicForJava.kt")
|
||||||
|
public void testEnumEntriesIntrinsicForJava() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicForJava.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicMultipleEnums.kt")
|
||||||
|
public void testEnumEntriesIntrinsicMultipleEnums() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicMultipleEnums.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumEntriesMultimodule.kt")
|
@TestMetadata("enumEntriesMultimodule.kt")
|
||||||
public void testEnumEntriesMultimodule() throws Exception {
|
public void testEnumEntriesMultimodule() throws Exception {
|
||||||
|
|||||||
+12
@@ -16693,6 +16693,18 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicForJava.kt")
|
||||||
|
public void testEnumEntriesIntrinsicForJava() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicForJava.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicMultipleEnums.kt")
|
||||||
|
public void testEnumEntriesIntrinsicMultipleEnums() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicMultipleEnums.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumEntriesMultimodule.kt")
|
@TestMetadata("enumEntriesMultimodule.kt")
|
||||||
public void testEnumEntriesMultimodule() throws Exception {
|
public void testEnumEntriesMultimodule() throws Exception {
|
||||||
|
|||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.jvm.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.EnumEntriesIntrinsicMappingsCache
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.findEnumValuesFunction
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irSetField
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
|
import org.jetbrains.kotlin.ir.types.typeWith
|
||||||
|
import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
// This class generates synthetic `$EntriesIntrinsicMappings` classes which cache the result of calling the `enumEntries` intrinsic
|
||||||
|
// on Java enums and on old (pre-1.9) Kotlin enums.
|
||||||
|
//
|
||||||
|
// `$EntriesIntrinsicMappings` classes are exactly the same as `$EntriesMappings` classes generated in `EnumExternalEntriesLowering`
|
||||||
|
// Unfortunately, we cannot reuse the logic from that lowering as is because, as opposed to the normal function call `E.entries`,
|
||||||
|
// the call to the intrinsic `enumEntries<E>()` is fully reified only during the codegen, where all IR of the module has already been
|
||||||
|
// lowered, notably:
|
||||||
|
// 1) All the `$EntriesMappings` have already been created for the `E.entries` calls, so we cannot easily reuse those classes, which is the
|
||||||
|
// the reason why we're generating new classes with a slightly different name, even though it might be suboptimal in cases when you have
|
||||||
|
// both `E.entries` and `enumEntries<E>` calls to the same enum in the same container.
|
||||||
|
// 2) Static initializers have been lowered, so we're generating the `<clinit>` method manually, as opposed to adding static init sections
|
||||||
|
// as `EnumExternalEntriesLowering` does.
|
||||||
|
class EnumEntriesIntrinsicMappingsCacheImpl(private val context: JvmBackendContext) : EnumEntriesIntrinsicMappingsCache() {
|
||||||
|
private val storage = mutableMapOf<IrClass, MappingsClass>()
|
||||||
|
|
||||||
|
private inner class MappingsClass(val containingClass: IrClass) {
|
||||||
|
val irClass = context.irFactory.buildClass {
|
||||||
|
name = Name.identifier("EntriesIntrinsicMappings")
|
||||||
|
origin = JvmLoweredDeclarationOrigin.ENUM_MAPPINGS_FOR_ENTRIES
|
||||||
|
}.apply {
|
||||||
|
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||||
|
parent = containingClass
|
||||||
|
}
|
||||||
|
|
||||||
|
val enums = hashMapOf<IrClass, IrField>()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun getEnumEntriesIntrinsicMappings(containingClass: IrClass, enumClass: IrClass): IrField {
|
||||||
|
val mappingsClass = storage.getOrPut(containingClass) { MappingsClass(containingClass) }
|
||||||
|
val field = mappingsClass.enums.getOrPut(enumClass) {
|
||||||
|
mappingsClass.irClass.addField {
|
||||||
|
name = Name.identifier("entries\$${mappingsClass.enums.size}")
|
||||||
|
type = context.ir.symbols.enumEntries.typeWith(enumClass.defaultType)
|
||||||
|
origin = JvmLoweredDeclarationOrigin.ENUM_MAPPINGS_FOR_ENTRIES
|
||||||
|
isFinal = true
|
||||||
|
isStatic = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateMappingsClasses() {
|
||||||
|
val backendContext = context
|
||||||
|
for (klass in storage.values) {
|
||||||
|
// Use the same origin and visibility for `<clinit>` as in StaticInitializersLowering.
|
||||||
|
val clinit = klass.irClass.addFunction(
|
||||||
|
"<clinit>", context.irBuiltIns.unitType, visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY,
|
||||||
|
isStatic = true, origin = JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER
|
||||||
|
)
|
||||||
|
clinit.body = context.createIrBuilder(clinit.symbol).irBlockBody(clinit) {
|
||||||
|
// Sort fields by name. Note that if there are a lot of calls to entries of different enums in the same container, it would
|
||||||
|
// result in the ordering "entries$0, entries$1, entries$10, entries$11, entries$12, ...", but it's not a big deal.
|
||||||
|
for ((enum, field) in klass.enums.entries.sortedBy { it.value.name }) {
|
||||||
|
// For each field, we're generating:
|
||||||
|
// entries$N = kotlin.enums.EnumEntriesKt.enumEntries(E.values())
|
||||||
|
val enumValues = enum.findEnumValuesFunction(backendContext)
|
||||||
|
+irSetField(
|
||||||
|
null, field,
|
||||||
|
irCall(backendContext.ir.symbols.createEnumEntries).apply {
|
||||||
|
putValueArgument(0, irCall(enumValues))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassCodegen.getOrCreate(klass.irClass, backendContext).generate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -33,6 +33,7 @@ import org.jetbrains.org.objectweb.asm.Type.INT_TYPE
|
|||||||
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
|
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||||
|
|
||||||
class IrInlineIntrinsicsSupport(
|
class IrInlineIntrinsicsSupport(
|
||||||
@@ -119,6 +120,9 @@ class IrInlineIntrinsicsSupport(
|
|||||||
|
|
||||||
override fun toKotlinType(type: IrType): KotlinType = type.toIrBasedKotlinType()
|
override fun toKotlinType(type: IrType): KotlinType = type.toIrBasedKotlinType()
|
||||||
|
|
||||||
|
override fun generateExternalEntriesForEnumTypeIfNeeded(type: IrType): FieldInsnNode? =
|
||||||
|
generateExternalEntriesForEnumTypeIfNeeded(type, classCodegen)
|
||||||
|
|
||||||
override fun reportSuspendTypeUnsupported() {
|
override fun reportSuspendTypeUnsupported() {
|
||||||
classCodegen.context.ktDiagnosticReporter.at(reportErrorsOn, containingFile).report(JvmBackendErrors.TYPEOF_SUSPEND_TYPE)
|
classCodegen.context.ktDiagnosticReporter.at(reportErrorsOn, containingFile).report(JvmBackendErrors.TYPEOF_SUSPEND_TYPE)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
|
|||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
class IrFrameMap : FrameMapBase<IrSymbol>() {
|
class IrFrameMap : FrameMapBase<IrSymbol>() {
|
||||||
@@ -349,3 +350,15 @@ val IrClass.reifiedTypeParameters: ReifiedTypeParametersUsages
|
|||||||
|
|
||||||
return tempReifiedTypeParametersUsages
|
return tempReifiedTypeParametersUsages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun generateExternalEntriesForEnumTypeIfNeeded(type: IrType, containingCodegen: ClassCodegen): FieldInsnNode? {
|
||||||
|
val irClass = type.getClass()
|
||||||
|
if (irClass == null || !irClass.isEnumClassWhichRequiresExternalEntries()) return null
|
||||||
|
|
||||||
|
val mappingsCache = containingCodegen.context.enumEntriesIntrinsicMappingsCache
|
||||||
|
val field = mappingsCache.getEnumEntriesIntrinsicMappings(containingCodegen.irClass, irClass)
|
||||||
|
return FieldInsnNode(
|
||||||
|
Opcodes.GETSTATIC, containingCodegen.typeMapper.mapClass(field.parentAsClass).internalName,
|
||||||
|
field.name.asString(), AsmTypes.ENUM_ENTRIES.descriptor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
+6
-2
@@ -80,8 +80,12 @@ object EnumEntries : IntrinsicMethod() {
|
|||||||
mv.checkcast(AsmTypes.ENUM_ENTRIES)
|
mv.checkcast(AsmTypes.ENUM_ENTRIES)
|
||||||
MaterialValue(codegen, AsmTypes.ENUM_ENTRIES, expression.type)
|
MaterialValue(codegen, AsmTypes.ENUM_ENTRIES, expression.type)
|
||||||
} else {
|
} else {
|
||||||
// TODO: support enumEntries for Java enums.
|
val getField = generateExternalEntriesForEnumTypeIfNeeded(type, codegen.classCodegen)
|
||||||
mv.invokestatic(typeMapper.mapType(type).internalName, "getEntries", Type.getMethodDescriptor(AsmTypes.ENUM_ENTRIES), false)
|
if (getField != null) {
|
||||||
|
mv.visitFieldInsn(getField.opcode, getField.owner, getField.name, getField.desc)
|
||||||
|
} else {
|
||||||
|
mv.invokestatic(typeMapper.mapType(type).internalName, "getEntries", Type.getMethodDescriptor(AsmTypes.ENUM_ENTRIES), false)
|
||||||
|
}
|
||||||
MaterialValue(codegen, AsmTypes.ENUM_ENTRIES, expression.type)
|
MaterialValue(codegen, AsmTypes.ENUM_ENTRIES, expression.type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
|
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.codegen.EnumEntriesIntrinsicMappingsCacheImpl
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.JvmIrIntrinsicExtension
|
import org.jetbrains.kotlin.backend.jvm.codegen.JvmIrIntrinsicExtension
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.getIoFile
|
import org.jetbrains.kotlin.backend.jvm.ir.getIoFile
|
||||||
@@ -343,6 +344,9 @@ open class JvmIrCodegenFactory(
|
|||||||
context.getIntrinsic = { symbol: IrFunctionSymbol ->
|
context.getIntrinsic = { symbol: IrFunctionSymbol ->
|
||||||
intrinsics.getIntrinsic(symbol) ?: generationExtensions.firstNotNullOfOrNull { it.getIntrinsic(symbol) }
|
intrinsics.getIntrinsic(symbol) ?: generationExtensions.firstNotNullOfOrNull { it.getIntrinsic(symbol) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.enumEntriesIntrinsicMappingsCache = EnumEntriesIntrinsicMappingsCacheImpl(context)
|
||||||
|
|
||||||
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
||||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||||
|
|
||||||
|
|||||||
+19
-5
@@ -6,10 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.jvm
|
package org.jetbrains.kotlin.backend.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.SameTypeNamedCompilerPhase
|
import org.jetbrains.kotlin.backend.common.phaser.*
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.performByIrFile
|
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.then
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
|
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
@@ -47,6 +44,22 @@ private class FileCodegen(private val context: JvmBackendContext, private val ge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val generateAdditionalClassesPhase = SameTypeNamedCompilerPhase(
|
||||||
|
"GenerateAdditionalClasses",
|
||||||
|
"Generate additional classes that were requested during codegen",
|
||||||
|
lower = object : SameTypeCompilerPhase<JvmBackendContext, IrModuleFragment> {
|
||||||
|
override fun invoke(
|
||||||
|
phaseConfig: PhaseConfigurationService,
|
||||||
|
phaserState: PhaserState<IrModuleFragment>,
|
||||||
|
context: JvmBackendContext,
|
||||||
|
input: IrModuleFragment,
|
||||||
|
): IrModuleFragment {
|
||||||
|
context.enumEntriesIntrinsicMappingsCache.generateMappingsClasses()
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Generate multifile facades first, to compute and store JVM signatures of const properties which are later used
|
// Generate multifile facades first, to compute and store JVM signatures of const properties which are later used
|
||||||
// when serializing metadata in the multifile parts.
|
// when serializing metadata in the multifile parts.
|
||||||
// TODO: consider dividing codegen itself into separate phases (bytecode generation, metadata serialization) to avoid this
|
// TODO: consider dividing codegen itself into separate phases (bytecode generation, metadata serialization) to avoid this
|
||||||
@@ -55,7 +68,8 @@ internal val jvmCodegenPhases = SameTypeNamedCompilerPhase(
|
|||||||
description = "Code generation",
|
description = "Code generation",
|
||||||
nlevels = 1,
|
nlevels = 1,
|
||||||
lower = codegenPhase(generateMultifileFacade = true) then
|
lower = codegenPhase(generateMultifileFacade = true) then
|
||||||
codegenPhase(generateMultifileFacade = false)
|
codegenPhase(generateMultifileFacade = false) then
|
||||||
|
generateAdditionalClassesPhase
|
||||||
)
|
)
|
||||||
|
|
||||||
// This property is needed to avoid dependencies from "leaf" modules (cli, tests-common-new) on backend.jvm:lower.
|
// This property is needed to avoid dependencies from "leaf" modules (cli, tests-common-new) on backend.jvm:lower.
|
||||||
|
|||||||
+7
-24
@@ -11,7 +11,8 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
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.isInCurrentModule
|
import org.jetbrains.kotlin.backend.jvm.ir.findEnumValuesFunction
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.isEnumClassWhichRequiresExternalEntries
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||||
@@ -26,7 +27,8 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||||
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.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
@@ -60,6 +62,8 @@ internal val enumExternalEntriesPhase = makeIrFilePhase(
|
|||||||
* // F.kt
|
* // F.kt
|
||||||
* FKt$EntriesMappings.entries$1
|
* FKt$EntriesMappings.entries$1
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
|
* There's similar code which handles the `enumEntries<Enum>()` intrinsic code generation in `EnumEntriesIntrinsicMappingsCacheImpl`.
|
||||||
*/
|
*/
|
||||||
class EnumExternalEntriesLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
class EnumExternalEntriesLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
@@ -99,33 +103,12 @@ class EnumExternalEntriesLowering(private val context: JvmBackendContext) : File
|
|||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
val owner = expression.symbol.owner as? IrSimpleFunction
|
val owner = expression.symbol.owner as? IrSimpleFunction
|
||||||
val parentClass = owner?.parent as? IrClass ?: return super.visitCall(expression)
|
val parentClass = owner?.parent as? IrClass ?: return super.visitCall(expression)
|
||||||
/*
|
val shouldBeLowered = owner.name == SpecialNames.ENUM_GET_ENTRIES && parentClass.isEnumClassWhichRequiresExternalEntries()
|
||||||
* Candidates for lowering:
|
|
||||||
* * Java enums
|
|
||||||
* * Kotlin enums that have no 'getEntries' function (thus compiled with pre-1.8 LV/AV)
|
|
||||||
*/
|
|
||||||
val shouldBeLowered = parentClass.isEnumClass &&
|
|
||||||
owner.name == SpecialNames.ENUM_GET_ENTRIES &&
|
|
||||||
(parentClass.isFromJava() || !parentClass.hasEnumEntriesFunction())
|
|
||||||
if (!shouldBeLowered) return super.visitCall(expression)
|
if (!shouldBeLowered) return super.visitCall(expression)
|
||||||
val field = state!!.getEntriesFieldForEnum(parentClass)
|
val field = state!!.getEntriesFieldForEnum(parentClass)
|
||||||
return IrGetFieldImpl(expression.startOffset, expression.endOffset, field.symbol, field.type)
|
return IrGetFieldImpl(expression.startOffset, expression.endOffset, field.symbol, field.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrClass.hasEnumEntriesFunction(): Boolean {
|
|
||||||
// Enums from other modules are always loaded with a property `entries` which has a getter `<get-entries>`.
|
|
||||||
// Enums from the current module will have a property `entries` if they are unlowered yet (i.e. enum is declared in another file
|
|
||||||
// which will be lowered after the file with the call site), or a function `<get-entries>` if they are already lowered.
|
|
||||||
return functions.any { it.isGetEntries() }
|
|
||||||
|| (properties.any { it.getter?.isGetEntries() == true } && isInCurrentModule())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrSimpleFunction.isGetEntries(): Boolean =
|
|
||||||
name.toString() == "<get-entries>"
|
|
||||||
&& dispatchReceiverParameter == null
|
|
||||||
&& extensionReceiverParameter == null
|
|
||||||
&& valueParameters.isEmpty()
|
|
||||||
|
|
||||||
override fun visitClassNew(declaration: IrClass): IrStatement {
|
override fun visitClassNew(declaration: IrClass): IrStatement {
|
||||||
val oldState = state
|
val oldState = state
|
||||||
val mappingState = EntriesMappingState()
|
val mappingState = EntriesMappingState()
|
||||||
|
|||||||
+3
-10
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.irCatch
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
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.findEnumValuesFunction
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
|
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
@@ -23,7 +24,8 @@ import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.types.getClass
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -167,12 +169,3 @@ private class MappedEnumWhenLowering(override val context: JvmBackendContext) :
|
|||||||
return declaration
|
return declaration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrClass.findEnumValuesFunction(context: JvmBackendContext) = functions.single {
|
|
||||||
it.name.toString() == "values"
|
|
||||||
&& it.dispatchReceiverParameter == null
|
|
||||||
&& it.extensionReceiverParameter == null
|
|
||||||
&& it.valueParameters.isEmpty()
|
|
||||||
&& it.returnType.isBoxedArray
|
|
||||||
&& it.returnType.getArrayElementType(context.irBuiltIns).classOrNull == this.symbol
|
|
||||||
}
|
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.jvm
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
|
|
||||||
|
abstract class EnumEntriesIntrinsicMappingsCache {
|
||||||
|
abstract fun getEnumEntriesIntrinsicMappings(containingClass: IrClass, enumClass: IrClass): IrField
|
||||||
|
|
||||||
|
abstract fun generateMappingsClasses()
|
||||||
|
}
|
||||||
@@ -114,6 +114,8 @@ class JvmBackendContext(
|
|||||||
|
|
||||||
lateinit var getIntrinsic: (IrFunctionSymbol) -> IntrinsicMarker?
|
lateinit var getIntrinsic: (IrFunctionSymbol) -> IntrinsicMarker?
|
||||||
|
|
||||||
|
lateinit var enumEntriesIntrinsicMappingsCache: EnumEntriesIntrinsicMappingsCache
|
||||||
|
|
||||||
// Store evaluated SMAP for anonymous classes. Used only with IR inliner.
|
// Store evaluated SMAP for anonymous classes. Used only with IR inliner.
|
||||||
val typeToCachedSMAP = mutableMapOf<Type, SMAP>()
|
val typeToCachedSMAP = mutableMapOf<Type, SMAP>()
|
||||||
|
|
||||||
|
|||||||
@@ -518,3 +518,30 @@ fun IrFunction.extensionReceiverName(state: GenerationState): String {
|
|||||||
|
|
||||||
fun IrFunction.isBridge(): Boolean =
|
fun IrFunction.isBridge(): Boolean =
|
||||||
origin == IrDeclarationOrigin.BRIDGE || origin == IrDeclarationOrigin.BRIDGE_SPECIAL
|
origin == IrDeclarationOrigin.BRIDGE || origin == IrDeclarationOrigin.BRIDGE_SPECIAL
|
||||||
|
|
||||||
|
// Enum requires external implementation of entries if it's either a Java enum, or a Kotlin enum compiled with pre-1.8 LV/AV.
|
||||||
|
fun IrClass.isEnumClassWhichRequiresExternalEntries(): Boolean =
|
||||||
|
isEnumClass && (isFromJava() || !hasEnumEntriesFunction())
|
||||||
|
|
||||||
|
private fun IrClass.hasEnumEntriesFunction(): Boolean {
|
||||||
|
// Enums from other modules are always loaded with a property `entries` which has a getter `<get-entries>`.
|
||||||
|
// Enums from the current module will have a property `entries` if they are unlowered yet (i.e. enum is declared in another file
|
||||||
|
// which will be lowered after the file with the call site), or a function `<get-entries>` if they are already lowered.
|
||||||
|
return functions.any { it.isGetEntries() }
|
||||||
|
|| (properties.any { it.getter?.isGetEntries() == true } && isInCurrentModule())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrSimpleFunction.isGetEntries(): Boolean =
|
||||||
|
name.toString() == "<get-entries>"
|
||||||
|
&& dispatchReceiverParameter == null
|
||||||
|
&& extensionReceiverParameter == null
|
||||||
|
&& valueParameters.isEmpty()
|
||||||
|
|
||||||
|
fun IrClass.findEnumValuesFunction(context: JvmBackendContext): IrSimpleFunction = functions.single {
|
||||||
|
it.name.toString() == "values"
|
||||||
|
&& it.dispatchReceiverParameter == null
|
||||||
|
&& it.extensionReceiverParameter == null
|
||||||
|
&& it.valueParameters.isEmpty()
|
||||||
|
&& it.returnType.isBoxedArray
|
||||||
|
&& it.returnType.getArrayElementType(context.irBuiltIns).classOrNull == this.symbol
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -226,7 +226,7 @@ object InlineTestUtil {
|
|||||||
override fun equals(other: Any?): Boolean = throw UnsupportedOperationException()
|
override fun equals(other: Any?): Boolean = throw UnsupportedOperationException()
|
||||||
override fun toString(): String = throw UnsupportedOperationException()
|
override fun toString(): String = throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
}!!
|
} ?: error("Generated class file has no @Metadata annotation: $file")
|
||||||
|
|
||||||
private class InlineInfo(val inlineMethods: Set<MethodInfo>, val binaryClasses: Map<String, KotlinJvmBinaryClass>)
|
private class InlineInfo(val inlineMethods: Set<MethodInfo>, val binaryClasses: Map<String, KotlinJvmBinaryClass>)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
// !OPT_IN: kotlin.ExperimentalStdlibApi
|
||||||
|
// WITH_STDLIB
|
||||||
|
// FILE: Z.java
|
||||||
|
|
||||||
|
public enum Z {
|
||||||
|
O, K
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: box.kt
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") // TODO: remove once KT-53154 is fixed.
|
||||||
|
|
||||||
|
import kotlin.enums.*
|
||||||
|
|
||||||
|
fun callFromOtherFunctionInTheSameFile(): EnumEntries<Z> = enumEntries<Z>()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val z = enumEntries<Z>()
|
||||||
|
if (z.toString() != "[O, K]") return "Fail 1: $z"
|
||||||
|
|
||||||
|
val z2 = enumEntries<Z>()
|
||||||
|
if (z2 !== z) return "Fail 2: another instance of EnumEntries is created"
|
||||||
|
|
||||||
|
val z3 = callFromOtherFunctionInTheSameFile()
|
||||||
|
if (z3 !== z) return "Fail 3: another instance of EnumEntries is created"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
// CHECK_BYTECODE_LISTING
|
||||||
|
// ^ Check that there's only one $EntriesIntrinsicMappings class, with three fields (entries$0, entries$1, entries$2).
|
||||||
|
|
||||||
|
// MODULE: lib
|
||||||
|
// !LANGUAGE: +EnumEntries
|
||||||
|
// FILE: X.kt
|
||||||
|
|
||||||
|
enum class X {
|
||||||
|
X1, X2
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Y.java
|
||||||
|
|
||||||
|
public enum Y {
|
||||||
|
Y1, Y2
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Z.java
|
||||||
|
|
||||||
|
public enum Z {
|
||||||
|
Z1, Z2
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: box(lib)
|
||||||
|
// !LANGUAGE: +EnumEntries
|
||||||
|
// !OPT_IN: kotlin.ExperimentalStdlibApi
|
||||||
|
// FILE: box.kt
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") // TODO: remove once KT-53154 is fixed.
|
||||||
|
|
||||||
|
import kotlin.enums.enumEntries
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val x = enumEntries<X>()
|
||||||
|
if (x.toString() != "[X1, X2]") return "Fail X: $x"
|
||||||
|
|
||||||
|
val y = enumEntries<Y>()
|
||||||
|
if (y.toString() != "[Y1, Y2]") return "Fail Y: $y"
|
||||||
|
|
||||||
|
val z = enumEntries<Z>()
|
||||||
|
if (z.toString() != "[Z1, Z2]") return "Fail Z: $z"
|
||||||
|
|
||||||
|
val xx = enumEntries<X>()
|
||||||
|
if (xx.toString() != "[X1, X2]") return "Fail X #2: $xx"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Module: lib
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class X {
|
||||||
|
// source: 'X.kt'
|
||||||
|
private synthetic final static field $ENTRIES: kotlin.enums.EnumEntries
|
||||||
|
private synthetic final static field $VALUES: X[]
|
||||||
|
public final enum static field X1: X
|
||||||
|
public final enum static field X2: X
|
||||||
|
private synthetic final static method $values(): X[]
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public static @org.jetbrains.annotations.NotNull method getEntries(): kotlin.enums.EnumEntries
|
||||||
|
public static method valueOf(p0: java.lang.String): X
|
||||||
|
public static method values(): X[]
|
||||||
|
}
|
||||||
|
Module: box
|
||||||
|
@kotlin.Metadata
|
||||||
|
public synthetic final class BoxKt$EntriesIntrinsicMappings {
|
||||||
|
// source: 'box.kt'
|
||||||
|
public synthetic final static field entries$0: kotlin.enums.EnumEntries
|
||||||
|
public synthetic final static field entries$1: kotlin.enums.EnumEntries
|
||||||
|
public synthetic final static field entries$2: kotlin.enums.EnumEntries
|
||||||
|
static method <clinit>(): void
|
||||||
|
public synthetic inner class BoxKt$EntriesIntrinsicMappings
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class BoxKt {
|
||||||
|
// source: 'box.kt'
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||||
|
public synthetic inner class BoxKt$EntriesIntrinsicMappings
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
// NO_CHECK_LAMBDA_INLINING
|
||||||
// !OPT_IN: kotlin.ExperimentalStdlibApi
|
// !OPT_IN: kotlin.ExperimentalStdlibApi
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// FILE: test/Z.java
|
// FILE: test/Z.java
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// !OPT_IN: kotlin.ExperimentalStdlibApi
|
// !OPT_IN: kotlin.ExperimentalStdlibApi
|
||||||
|
|||||||
@@ -19,4 +19,6 @@ fun foo() {
|
|||||||
enumEntries2<MyEnum>()
|
enumEntries2<MyEnum>()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 INVOKESTATIC kotlin/enums/EnumEntriesKt.enumEntries
|
// There should be one call to enumEntries in _1Kt$EntriesIntrinsicMappings.<clinit>.
|
||||||
|
// 2 GETSTATIC _1Kt\$EntriesIntrinsicMappings.entries\$0
|
||||||
|
// 1 INVOKESTATIC kotlin/enums/EnumEntriesKt.enumEntries
|
||||||
|
|||||||
+12
@@ -16693,6 +16693,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicForJava.kt")
|
||||||
|
public void testEnumEntriesIntrinsicForJava() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicForJava.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicMultipleEnums.kt")
|
||||||
|
public void testEnumEntriesIntrinsicMultipleEnums() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicMultipleEnums.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumEntriesMultimodule.kt")
|
@TestMetadata("enumEntriesMultimodule.kt")
|
||||||
public void testEnumEntriesMultimodule() throws Exception {
|
public void testEnumEntriesMultimodule() throws Exception {
|
||||||
|
|||||||
+12
@@ -16693,6 +16693,18 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicForJava.kt")
|
||||||
|
public void testEnumEntriesIntrinsicForJava() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicForJava.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("enumEntriesIntrinsicMultipleEnums.kt")
|
||||||
|
public void testEnumEntriesIntrinsicMultipleEnums() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicMultipleEnums.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("enumEntriesMultimodule.kt")
|
@TestMetadata("enumEntriesMultimodule.kt")
|
||||||
public void testEnumEntriesMultimodule() throws Exception {
|
public void testEnumEntriesMultimodule() throws Exception {
|
||||||
|
|||||||
+10
@@ -13786,6 +13786,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
runTest("compiler/testData/codegen/box/enum/enumEntriesInCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumEntriesIntrinsicForJava.kt")
|
||||||
|
public void testEnumEntriesIntrinsicForJava() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicForJava.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumEntriesIntrinsicMultipleEnums.kt")
|
||||||
|
public void testEnumEntriesIntrinsicMultipleEnums() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/enumEntriesIntrinsicMultipleEnums.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("enumEntriesMultimodule.kt")
|
@TestMetadata("enumEntriesMultimodule.kt")
|
||||||
public void testEnumEntriesMultimodule() throws Exception {
|
public void testEnumEntriesMultimodule() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/enumEntriesMultimodule.kt");
|
runTest("compiler/testData/codegen/box/enum/enumEntriesMultimodule.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user