IR: add IrClass.hasEnumEntries
This flag will be used on JVM to determine whether or not to generate
external enum entries mappings ("$EntriesMappings") classes. Note that
from the frontend's point of view, every enum has `entries`, so for
backend purposes we have to reach out to the underlying deserialized
data to read the flag from the metadata.
This commit is contained in:
committed by
Space Team
parent
db31f1f926
commit
c33c918bd4
+5
-2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.containingClassForLocalAttr
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
|
||||
import org.jetbrains.kotlin.fir.hasEnumEntries
|
||||
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
||||
@@ -138,7 +139,8 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
|
||||
isData = regularClass.isData,
|
||||
isValue = regularClass.isInline,
|
||||
isExpect = regularClass.isExpect,
|
||||
isFun = regularClass.isFun
|
||||
isFun = regularClass.isFun,
|
||||
hasEnumEntries = regularClass.hasEnumEntries,
|
||||
).apply {
|
||||
metadata = FirMetadataSource.Class(regularClass)
|
||||
}
|
||||
@@ -376,7 +378,8 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
|
||||
isData = false,
|
||||
isValue = false,
|
||||
isExpect = false,
|
||||
isFun = false
|
||||
isFun = false,
|
||||
hasEnumEntries = false,
|
||||
).apply {
|
||||
metadata = FirMetadataSource.CodeFragment(codeFragment)
|
||||
parent = containingFile
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.dispatchReceiverClassLookupTagOrNull
|
||||
import org.jetbrains.kotlin.fir.hasEnumEntries
|
||||
import org.jetbrains.kotlin.fir.isNewPlaceForBodyGeneration
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
@@ -109,6 +110,10 @@ class Fir2IrLazyClass(
|
||||
get() = fir.isFun
|
||||
set(_) = mutationNotSupported()
|
||||
|
||||
override var hasEnumEntries: Boolean
|
||||
get() = fir.hasEnumEntries
|
||||
set(_) = mutationNotSupported()
|
||||
|
||||
override var superTypes: List<IrType> by lazyVar(lock) {
|
||||
fir.superTypeRefs.map { it.toIrType(typeConverter) }
|
||||
}
|
||||
|
||||
@@ -51,6 +51,17 @@ abstract class IrClass : IrDeclarationBase(), IrPossiblyExternalDeclaration,
|
||||
|
||||
abstract var isFun: Boolean
|
||||
|
||||
/**
|
||||
* Returns true iff this is a class loaded from dependencies which has the `HAS_ENUM_ENTRIES`
|
||||
* metadata flag set.
|
||||
* This flag is useful for Kotlin/JVM to determine whether an enum class from dependency
|
||||
* actually has the `entries` property
|
||||
* in its bytecode, as opposed to whether it has it in its member scope, which is true even for
|
||||
* enum classes compiled by
|
||||
* old versions of Kotlin which did not support the EnumEntries language feature.
|
||||
*/
|
||||
abstract var hasEnumEntries: Boolean
|
||||
|
||||
abstract val source: SourceElement
|
||||
|
||||
abstract var superTypes: List<IrType>
|
||||
|
||||
@@ -60,6 +60,7 @@ interface IrFactory {
|
||||
isValue: Boolean = false,
|
||||
isExpect: Boolean = false,
|
||||
isFun: Boolean = false,
|
||||
hasEnumEntries: Boolean = false,
|
||||
source: SourceElement = SourceElement.NO_SOURCE,
|
||||
): IrClass
|
||||
|
||||
@@ -300,6 +301,7 @@ interface IrFactory {
|
||||
isValue,
|
||||
isExpect,
|
||||
isFun,
|
||||
false,
|
||||
source,
|
||||
)
|
||||
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ class IrClassBuilder : IrDeclarationBuilder() {
|
||||
var isValue: Boolean = false
|
||||
var isExpect: Boolean = false
|
||||
var isFun: Boolean = false
|
||||
var hasEnumEntries: Boolean = false
|
||||
|
||||
fun updateFrom(from: IrClass) {
|
||||
super.updateFrom(from)
|
||||
@@ -33,5 +34,6 @@ class IrClassBuilder : IrDeclarationBuilder() {
|
||||
isValue = from.isValue
|
||||
isExpect = from.isExpect
|
||||
isFun = from.isFun
|
||||
hasEnumEntries = from.hasEnumEntries
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ internal fun IrFactory.buildClass(builder: IrClassBuilder): IrClass = with(build
|
||||
isValue = isValue,
|
||||
isExpect = isExpect,
|
||||
isFun = isFun,
|
||||
hasEnumEntries = hasEnumEntries,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ open class IrClassImpl(
|
||||
override var isValue: Boolean = false,
|
||||
override var isExpect: Boolean = false,
|
||||
override var isFun: Boolean = false,
|
||||
override var hasEnumEntries: Boolean = false,
|
||||
override val source: SourceElement = SourceElement.NO_SOURCE,
|
||||
override val factory: IrFactory = IrFactoryImpl
|
||||
) : IrClass() {
|
||||
|
||||
@@ -50,11 +50,12 @@ abstract class AbstractIrFactoryImpl : IrFactory {
|
||||
isValue: Boolean,
|
||||
isExpect: Boolean,
|
||||
isFun: Boolean,
|
||||
hasEnumEntries: Boolean,
|
||||
source: SourceElement,
|
||||
): IrClass =
|
||||
IrClassImpl(
|
||||
startOffset, endOffset, origin, symbol, name, kind, visibility, modality,
|
||||
isCompanion, isInner, isData, isExternal, isValue, isExpect, isFun, source,
|
||||
isCompanion, isInner, isData, isExternal, isValue, isExpect, isFun, hasEnumEntries, source,
|
||||
factory = this
|
||||
)
|
||||
|
||||
|
||||
+2
@@ -62,6 +62,7 @@ class IrFactoryImplForJsIC(override val stageController: StageController) : Abst
|
||||
isValue: Boolean,
|
||||
isExpect: Boolean,
|
||||
isFun: Boolean,
|
||||
hasEnumEntries: Boolean,
|
||||
source: SourceElement
|
||||
): IrClass {
|
||||
return super.createClass(
|
||||
@@ -80,6 +81,7 @@ class IrFactoryImplForJsIC(override val stageController: StageController) : Abst
|
||||
isValue,
|
||||
isExpect,
|
||||
isFun,
|
||||
hasEnumEntries,
|
||||
source,
|
||||
).register()
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ class IrLazyClass(
|
||||
override var isValue: Boolean,
|
||||
override var isExpect: Boolean,
|
||||
override var isFun: Boolean,
|
||||
override var hasEnumEntries: Boolean,
|
||||
override val stubGenerator: DeclarationStubGenerator,
|
||||
override val typeTranslator: TypeTranslator
|
||||
) : IrClass(), IrLazyDeclarationBase, DeserializableClass {
|
||||
|
||||
@@ -36,6 +36,7 @@ class LazyIrFactory(
|
||||
isValue: Boolean,
|
||||
isExpect: Boolean,
|
||||
isFun: Boolean,
|
||||
hasEnumEntries: Boolean,
|
||||
source: SourceElement
|
||||
): IrClass = if (symbol.isBound)
|
||||
symbol.owner
|
||||
@@ -56,6 +57,7 @@ class LazyIrFactory(
|
||||
isValue,
|
||||
isExpect,
|
||||
isFun,
|
||||
hasEnumEntries,
|
||||
source,
|
||||
)
|
||||
|
||||
|
||||
@@ -24,11 +24,14 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.lazy.*
|
||||
import org.jetbrains.kotlin.ir.linkage.IrProvider
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.resolve.isValueClass
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
@@ -277,6 +280,7 @@ abstract class DeclarationStubGenerator(
|
||||
isValue = isValueClass(),
|
||||
isExpect = isExpect,
|
||||
isFun = isFun,
|
||||
hasEnumEntries = descriptor is DeserializedClassDescriptor && descriptor.hasEnumEntriesMetadataFlag,
|
||||
stubGenerator = this@DeclarationStubGenerator,
|
||||
typeTranslator = typeTranslator
|
||||
)
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.util
|
||||
|
||||
import org.jetbrains.kotlin.ir.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -157,6 +159,7 @@ open class DeepCopyIrTreeWithSymbols(
|
||||
isValue = declaration.isValue,
|
||||
isExpect = declaration.isExpect,
|
||||
isFun = declaration.isFun,
|
||||
hasEnumEntries = declaration.hasEnumEntries,
|
||||
).apply {
|
||||
transformAnnotations(declaration)
|
||||
copyTypeParametersFrom(declaration)
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.resolve.isValueClass
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
val ParameterDescriptor.indexOrMinusOne: Int
|
||||
@@ -52,5 +53,6 @@ fun IrFactory.createIrClassFromDescriptor(
|
||||
isValue = descriptor.isValueClass(),
|
||||
isExpect = descriptor.isExpect,
|
||||
isFun = descriptor.isFun,
|
||||
hasEnumEntries = descriptor is DeserializedClassDescriptor && descriptor.hasEnumEntriesMetadataFlag,
|
||||
source = descriptor.source,
|
||||
)
|
||||
|
||||
@@ -273,6 +273,15 @@ object IrTree : AbstractTreeBuilder() {
|
||||
+field("isFun", boolean) {
|
||||
useFieldInIrFactory(defaultValue = false)
|
||||
}
|
||||
+field("hasEnumEntries", boolean) {
|
||||
useFieldInIrFactory(defaultValue = false)
|
||||
kdoc = """
|
||||
Returns true iff this is a class loaded from dependencies which has the `HAS_ENUM_ENTRIES` metadata flag set.
|
||||
This flag is useful for Kotlin/JVM to determine whether an enum class from dependency actually has the `entries` property
|
||||
in its bytecode, as opposed to whether it has it in its member scope, which is true even for enum classes compiled by
|
||||
old versions of Kotlin which did not support the EnumEntries language feature.
|
||||
""".trimIndent()
|
||||
}
|
||||
+field("source", type<SourceElement>(), mutable = false) {
|
||||
useFieldInIrFactory(defaultValue = code("%T.NO_SOURCE", SourceElement::class))
|
||||
}
|
||||
|
||||
+9
-4
@@ -104,6 +104,7 @@ internal fun printFactory(generationPath: File, model: Model): GeneratedFile {
|
||||
parameter("isExpect")
|
||||
parameter("isFun")
|
||||
parameter("source")
|
||||
defaultValue["hasEnumEntries"] = false
|
||||
}
|
||||
|
||||
addDeprecatedFunction(replacement("createConstructor")) {
|
||||
@@ -272,14 +273,11 @@ internal fun printFactory(generationPath: File, model: Model): GeneratedFile {
|
||||
}
|
||||
|
||||
private class DeprecatedFunctionBuilder(private val replacement: FunSpec) {
|
||||
|
||||
val deprecatedFunctionParameterSpecs = mutableListOf<ParameterSpec>()
|
||||
|
||||
var oldName = replacement.name
|
||||
|
||||
var returnType = replacement.returnType
|
||||
|
||||
var deprecationMessage: String? = null
|
||||
val defaultValue = mutableMapOf<String, Any?>()
|
||||
|
||||
fun parameter(name: String, removeDefaultValue: Boolean = false) {
|
||||
val replacementParameter =
|
||||
@@ -322,6 +320,13 @@ private fun TypeSpec.Builder.addDeprecatedFunction(
|
||||
indent()
|
||||
add("%N,\n", parameter)
|
||||
unindent()
|
||||
} else {
|
||||
val value = builder.defaultValue[parameter.name]
|
||||
if (value != null) {
|
||||
indent()
|
||||
add("$value,\n")
|
||||
unindent()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -374,6 +374,7 @@ class IrDeclarationDeserializer(
|
||||
isValue = flags.isValue,
|
||||
isExpect = flags.isExpect,
|
||||
isFun = flags.isFun,
|
||||
hasEnumEntries = flags.hasEnumEntries,
|
||||
)
|
||||
}.usingParent {
|
||||
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ value class ClassFlags(val flags: Long) {
|
||||
val isExpect: Boolean get() = IrFlags.IS_EXPECT_CLASS.get(flags.toInt())
|
||||
val isExternal: Boolean get() = IrFlags.IS_EXTERNAL_CLASS.get(flags.toInt())
|
||||
val isFun: Boolean get() = IrFlags.IS_FUN_INTERFACE.get(flags.toInt())
|
||||
val hasEnumEntries: Boolean get() = IrFlags.HAS_ENUM_ENTRIES.get(flags.toInt())
|
||||
|
||||
companion object {
|
||||
fun encode(clazz: IrClass, languageVersionSettings: LanguageVersionSettings): Long {
|
||||
|
||||
+3
-1
@@ -52,9 +52,11 @@ class DeserializedClassDescriptor(
|
||||
VersionRequirementTable.create(classProto.versionRequirementTable), metadataVersion
|
||||
)
|
||||
|
||||
val hasEnumEntriesMetadataFlag: Boolean = Flags.HAS_ENUM_ENTRIES.get(classProto.flags)
|
||||
|
||||
private val staticScope =
|
||||
if (kind == ClassKind.ENUM_CLASS) {
|
||||
val enumEntriesCanBeUsed = Flags.HAS_ENUM_ENTRIES.get(classProto.flags) ||
|
||||
val enumEntriesCanBeUsed = hasEnumEntriesMetadataFlag ||
|
||||
c.components.enumEntriesDeserializationSupport.canSynthesizeEnumEntries() == true
|
||||
StaticScopeForKotlinEnum(c.storageManager, this, enumEntriesCanBeUsed)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user