Don't add Enum.entries to scope if it can't be called

^KT-53929 Fixed
This commit is contained in:
Roman Efremov
2023-01-03 14:44:35 +01:00
parent 2dc3871954
commit 878608b7b2
14 changed files with 88 additions and 19 deletions
@@ -63,7 +63,8 @@ class DeserializerForClassfileDecompiler(
LookupTracker.DO_NOTHING, JavaFlexibleTypeDeserializer, emptyList(), notFoundClasses, LookupTracker.DO_NOTHING, JavaFlexibleTypeDeserializer, emptyList(), notFoundClasses,
ContractDeserializerImpl(configuration, storageManager), ContractDeserializerImpl(configuration, storageManager),
extensionRegistryLite = JvmProtoBufUtil.EXTENSION_REGISTRY, extensionRegistryLite = JvmProtoBufUtil.EXTENSION_REGISTRY,
samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()) samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()),
enumEntriesDeserializationSupport = enumEntriesDeserializationSupport,
) )
} }
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.EnumEntriesDeserializationSupportImpl
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.EnumEntriesDeserializationSupport
import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierTypeSettings import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierTypeSettings
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
@@ -43,6 +45,9 @@ abstract class DeserializerForDecompilerBase(val directoryPackageFqName: FqName)
} }
} }
protected val enumEntriesDeserializationSupport: EnumEntriesDeserializationSupport =
EnumEntriesDeserializationSupportImpl(moduleDescriptor.platform)
override fun resolveTopLevelClass(classId: ClassId) = deserializationComponents.deserializeClass(classId) override fun resolveTopLevelClass(classId: ClassId) = deserializationComponents.deserializeClass(classId)
protected fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor = protected fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor =
@@ -40,7 +40,8 @@ class KotlinMetadataDeserializerForDecompiler(
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses, LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses,
ContractDeserializer.DEFAULT, ContractDeserializer.DEFAULT,
extensionRegistryLite = serializerProtocol.extensionRegistry, extensionRegistryLite = serializerProtocol.extensionRegistry,
samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()) samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()),
enumEntriesDeserializationSupport = enumEntriesDeserializationSupport,
) )
} }
@@ -0,0 +1,16 @@
/*
* 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.resolve.jvm
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.serialization.deserialization.EnumEntriesDeserializationSupport
class EnumEntriesDeserializationSupportImpl(
private val platform: TargetPlatform?,
) : EnumEntriesDeserializationSupport {
override fun canSynthesizeEnumEntries(): Boolean = platform.isJvm()
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.EnumEntriesDeserializationSupportImpl
import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.sam.SamConversionResolver import org.jetbrains.kotlin.resolve.sam.SamConversionResolver
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -61,7 +62,8 @@ class OptionalAnnotationPackageFragmentProvider(
notFoundClasses, notFoundClasses,
ContractDeserializer.DEFAULT, ContractDeserializer.DEFAULT,
extensionRegistryLite = serializerProtocol.extensionRegistry, extensionRegistryLite = serializerProtocol.extensionRegistry,
samConversionResolver = SamConversionResolver.Empty samConversionResolver = SamConversionResolver.Empty,
enumEntriesDeserializationSupport = EnumEntriesDeserializationSupportImpl(module.platform),
) )
} }
@@ -135,7 +135,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
this.kind = classLikeInfo.getClassKind(); this.kind = classLikeInfo.getClassKind();
this.staticScope = kind == ClassKind.ENUM_CLASS ? this.staticScope = kind == ClassKind.ENUM_CLASS ?
new StaticScopeForKotlinEnum( new StaticScopeForKotlinEnum(
storageManager, this storageManager, this, /* enumEntriesCanBeUsed = */ true
) : MemberScope.Empty.INSTANCE; ) : MemberScope.Empty.INSTANCE;
this.typeConstructor = new LazyClassTypeConstructor(); this.typeConstructor = new LazyClassTypeConstructor();
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.library.unresolvedDependencies
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.parentOrNull import org.jetbrains.kotlin.name.parentOrNull
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.sam.SamConversionResolverImpl import org.jetbrains.kotlin.resolve.sam.SamConversionResolverImpl
import org.jetbrains.kotlin.serialization.deserialization.* import org.jetbrains.kotlin.serialization.deserialization.*
@@ -152,6 +153,10 @@ class KlibMetadataModuleDescriptorFactoryImpl(
KlibMetadataSerializerProtocol KlibMetadataSerializerProtocol
) )
val enumEntriesDeserializationSupport = object : EnumEntriesDeserializationSupport {
override fun canSynthesizeEnumEntries(): Boolean = moduleDescriptor.platform.isJvm()
}
val components = DeserializationComponents( val components = DeserializationComponents(
storageManager, storageManager,
moduleDescriptor, moduleDescriptor,
@@ -168,7 +173,8 @@ class KlibMetadataModuleDescriptorFactoryImpl(
ContractDeserializerImpl(configuration, storageManager), ContractDeserializerImpl(configuration, storageManager),
extensionRegistryLite = KlibMetadataSerializerProtocol.extensionRegistry, extensionRegistryLite = KlibMetadataSerializerProtocol.extensionRegistry,
samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()), samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()),
platformDependentTypeTransformer = platformDependentTypeTransformer platformDependentTypeTransformer = platformDependentTypeTransformer,
enumEntriesDeserializationSupport = enumEntriesDeserializationSupport,
) )
fragmentsToInitialize.forEach { fragmentsToInitialize.forEach {
@@ -52,7 +52,8 @@ class JvmBuiltInsPackageFragmentProvider(
additionalClassPartsProvider, platformDependentDeclarationFilter, additionalClassPartsProvider, platformDependentDeclarationFilter,
BuiltInSerializerProtocol.extensionRegistry, BuiltInSerializerProtocol.extensionRegistry,
kotlinTypeChecker, kotlinTypeChecker,
samConversionResolver samConversionResolver,
enumEntriesDeserializationSupport = JvmEnumEntriesDeserializationSupport,
) )
} }
@@ -27,11 +27,7 @@ import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclara
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.JavaClassesTracker
import org.jetbrains.kotlin.load.java.JavaModuleAnnotationsProvider
import org.jetbrains.kotlin.load.java.JavaTypeEnhancementState
import org.jetbrains.kotlin.load.java.components.JavaPropertyInitializerEvaluator import org.jetbrains.kotlin.load.java.components.JavaPropertyInitializerEvaluator
import org.jetbrains.kotlin.load.java.components.JavaResolverCache import org.jetbrains.kotlin.load.java.components.JavaResolverCache
import org.jetbrains.kotlin.load.java.components.SignaturePropagator import org.jetbrains.kotlin.load.java.components.SignaturePropagator
@@ -82,7 +78,8 @@ class DeserializationComponentsForJava(
platformDependentDeclarationFilter = jvmBuiltIns?.customizer ?: PlatformDependentDeclarationFilter.NoPlatformDependent, platformDependentDeclarationFilter = jvmBuiltIns?.customizer ?: PlatformDependentDeclarationFilter.NoPlatformDependent,
extensionRegistryLite = JvmProtoBufUtil.EXTENSION_REGISTRY, extensionRegistryLite = JvmProtoBufUtil.EXTENSION_REGISTRY,
kotlinTypeChecker = kotlinTypeChecker, samConversionResolver = SamConversionResolverImpl(storageManager, emptyList()), kotlinTypeChecker = kotlinTypeChecker, samConversionResolver = SamConversionResolverImpl(storageManager, emptyList()),
typeAttributeTranslators = typeAttributeTranslators.translators typeAttributeTranslators = typeAttributeTranslators.translators,
enumEntriesDeserializationSupport = JvmEnumEntriesDeserializationSupport,
) )
} }
@@ -31,7 +31,8 @@ import org.jetbrains.kotlin.utils.SmartList
// We don't need to track lookups here since this scope used only for introduce special Enum class members // We don't need to track lookups here since this scope used only for introduce special Enum class members
class StaticScopeForKotlinEnum( class StaticScopeForKotlinEnum(
storageManager: StorageManager, storageManager: StorageManager,
private val containingClass: ClassDescriptor private val containingClass: ClassDescriptor,
private val enumEntriesCanBeUsed: Boolean,
) : MemberScopeImpl() { ) : MemberScopeImpl() {
init { init {
assert(containingClass.kind == ClassKind.ENUM_CLASS) { "Class should be an enum: $containingClass" } assert(containingClass.kind == ClassKind.ENUM_CLASS) { "Class should be an enum: $containingClass" }
@@ -44,7 +45,12 @@ class StaticScopeForKotlinEnum(
} }
private val properties: List<PropertyDescriptor> by storageManager.createLazyValue { private val properties: List<PropertyDescriptor> by storageManager.createLazyValue {
listOfNotNull(createEnumEntriesProperty(containingClass)) if (enumEntriesCanBeUsed) {
// It still might be filtered out later in tower resolve if feature disabled
listOfNotNull(createEnumEntriesProperty(containingClass))
} else {
emptyList()
}
} }
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = functions + properties override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = functions + properties
@@ -0,0 +1,25 @@
/*
* 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.serialization.deserialization
interface EnumEntriesDeserializationSupport {
/**
* Determines whether `Enum.entries` property can be synthesized for enums in this module,
* when this property is not present in compiled code.
* Returns `null` if it's not known.
*/
fun canSynthesizeEnumEntries(): Boolean?
object Default : EnumEntriesDeserializationSupport {
override fun canSynthesizeEnumEntries(): Boolean? = null
}
}
object JvmEnumEntriesDeserializationSupport : EnumEntriesDeserializationSupport {
// In JVM modules "entries" can be called even on enum compiled without this property.
override fun canSynthesizeEnumEntries(): Boolean = true
}
@@ -55,7 +55,8 @@ class DeserializationComponents(
val kotlinTypeChecker: NewKotlinTypeChecker = NewKotlinTypeChecker.Default, val kotlinTypeChecker: NewKotlinTypeChecker = NewKotlinTypeChecker.Default,
val samConversionResolver: SamConversionResolver, val samConversionResolver: SamConversionResolver,
val platformDependentTypeTransformer: PlatformDependentTypeTransformer = PlatformDependentTypeTransformer.None, val platformDependentTypeTransformer: PlatformDependentTypeTransformer = PlatformDependentTypeTransformer.None,
val typeAttributeTranslators: List<TypeAttributeTranslator> = listOf(DefaultTypeAttributeTranslator) val typeAttributeTranslators: List<TypeAttributeTranslator> = listOf(DefaultTypeAttributeTranslator),
val enumEntriesDeserializationSupport: EnumEntriesDeserializationSupport = EnumEntriesDeserializationSupport.Default,
) { ) {
val classDeserializer: ClassDeserializer = ClassDeserializer(this) val classDeserializer: ClassDeserializer = ClassDeserializer(this)
@@ -53,10 +53,13 @@ class DeserializedClassDescriptor(
) )
private val staticScope = private val staticScope =
if (kind == ClassKind.ENUM_CLASS) if (kind == ClassKind.ENUM_CLASS) {
StaticScopeForKotlinEnum(c.storageManager, this) val enumEntriesCanBeUsed = Flags.HAS_ENUM_ENTRIES.get(classProto.flags) ||
else c.components.enumEntriesDeserializationSupport.canSynthesizeEnumEntries() == true
StaticScopeForKotlinEnum(c.storageManager, this, enumEntriesCanBeUsed)
} else {
MemberScope.Empty MemberScope.Empty
}
private val typeConstructor = DeserializedClassTypeConstructor() private val typeConstructor = DeserializedClassTypeConstructor()
@@ -64,6 +64,10 @@ fun createKotlinJavascriptPackageFragmentProvider(
val notFoundClasses = NotFoundClasses(storageManager, module) val notFoundClasses = NotFoundClasses(storageManager, module)
val enumEntriesDeserializationSupport = object : EnumEntriesDeserializationSupport {
override fun canSynthesizeEnumEntries(): Boolean = false
}
val components = DeserializationComponents( val components = DeserializationComponents(
storageManager, storageManager,
module, module,
@@ -80,7 +84,8 @@ fun createKotlinJavascriptPackageFragmentProvider(
ContractDeserializerImpl(configuration, storageManager), ContractDeserializerImpl(configuration, storageManager),
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent, platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent,
extensionRegistryLite = JsSerializerProtocol.extensionRegistry, extensionRegistryLite = JsSerializerProtocol.extensionRegistry,
samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()) samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()),
enumEntriesDeserializationSupport = enumEntriesDeserializationSupport,
) )
for (packageFragment in packageFragments.filterIsInstance<KotlinJavascriptPackageFragment>()) { for (packageFragment in packageFragments.filterIsInstance<KotlinJavascriptPackageFragment>()) {