KT-44821 [Sealed Interfaces]: when-exhaustiveness failure in IDE

Compiler check for 'when' exhaustiveness requires that module
descriptors of a sealed class and its inheritors are the same (reference
identity matters). Prior to this commit and under some conditions they
were not. Details follow below.

Resolution related data structures (resolution facades) are organized
into trees (sdks, libs, and modules have their own nodes/facades,
module/class descriptors are stored inside). And the trees themselves
are put into a map associating so called PlatformAnalysisSettings and
GlobalFacades (plays a role of a root). PlatformAnalysisSettings is an
abstraction describing target platform and sdk of a module. The more
combinations exist for a project the more facades are used. Please, see
KotlinCacheService for more details.

So why a module can have multiple ModuleDescriptor-s?
Every tree mentioned above is an isolated resolution environment
containing its own instances of the outer world descriptors. Say, if a
project has modules X, Y, Z and we consider X then all three might have
their own vision of X, i.e. 3 descriptors exist at a time.

What descriptor instance does compiler get?
The path starts when the user opens a file in the editor and
highlighting pass starts (see usages of
ResolutionUtils#analyzeWithAllCompilerChecks). Module descriptor stored
in the resolution tree of the file's module gets injected into the
compiler's context. Starting from this moment compiler sees other
modules through the prism of a single resolution facade (tree).
Descriptors residing outside are alien.

This commit allows IdeSealedClassInheritorsProvider to figure out what
PlatformAnalysisSettings are associated with the resolution facade (read
ModuleDescriptor) seen by the compiler. Later on the same facade is used
to provide correct instances of sealed inheritors back to the compiler.
This commit is contained in:
Andrei Klunnyi
2021-02-19 18:42:59 +01:00
parent 6ebd4b954c
commit f45af5ea0e
8 changed files with 105 additions and 63 deletions
@@ -12,8 +12,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.RESOLUTION_ANCHOR_PROVIDER_CAPABILITY
import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider
import org.jetbrains.kotlin.utils.checkWithAttachment
abstract class AbstractResolverForProject<M : ModuleInfo>(
@@ -22,8 +20,7 @@ abstract class AbstractResolverForProject<M : ModuleInfo>(
modules: Collection<M>,
protected val fallbackModificationTracker: ModificationTracker? = null,
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
protected val resolutionAnchorProvider: ResolutionAnchorProvider = ResolutionAnchorProvider.Default,
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory
) : ResolverForProject<M>() {
protected class ModuleData(
@@ -196,13 +193,15 @@ abstract class AbstractResolverForProject<M : ModuleInfo>(
return moduleData
}
protected open fun getAdditionalCapabilities(): Map<ModuleCapability<*>, Any?> = emptyMap()
private fun createModuleDescriptor(module: M): ModuleData {
val moduleDescriptor = ModuleDescriptorImpl(
module.name,
projectContext.storageManager,
builtInsForModule(module),
module.platform,
module.capabilities + listOf(RESOLUTION_ANCHOR_PROVIDER_CAPABILITY to resolutionAnchorProvider),
module.capabilities + getAdditionalCapabilities(),
module.stableName,
)
moduleInfoByDescriptor[moduleDescriptor] = module