[MPP] Allow smart casts for properties from dependsOn modules
Smartcasts for public properties from different module are not stable because module declaring a property in general can be compiled separately from the module using it. However, if client module has dependsOn relation with declaring module their simultaneous compilation is guaranteed which makes this smart cast safe. Cache all transitive 'expected by' modules in module dependencies. Extend test to check smart casts are allowed for properties from transitive 'expected by' dependencies and prohibited otherwise. ^KT-42754 Fixed
This commit is contained in:
@@ -155,13 +155,20 @@ class LazyModuleDependencies<M : ModuleInfo>(
|
||||
|
||||
override val allDependencies: List<ModuleDescriptorImpl> get() = dependencies()
|
||||
|
||||
override val expectedByDependencies by storageManager.createLazyValue {
|
||||
override val directExpectedByDependencies by storageManager.createLazyValue {
|
||||
module.expectedBy.map {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
resolverForProject.descriptorForModule(it as M)
|
||||
}
|
||||
}
|
||||
|
||||
override val allExpectedByDependencies: Set<ModuleDescriptorImpl> by storageManager.createLazyValue {
|
||||
collectAllExpectedByModules(module).mapTo(HashSet<ModuleDescriptorImpl>()) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
resolverForProject.descriptorForModule(it as M)
|
||||
}
|
||||
}
|
||||
|
||||
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
|
||||
get() =
|
||||
module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) {
|
||||
|
||||
@@ -9,3 +9,17 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
|
||||
val ModuleDescriptor.moduleInfo: ModuleInfo?
|
||||
get() = getCapability(ModuleInfo.Capability)
|
||||
|
||||
internal fun collectAllExpectedByModules(entryModule: ModuleInfo): Set<ModuleInfo> {
|
||||
val unprocessedModules = ArrayDeque<ModuleInfo>().apply { addAll(entryModule.expectedBy) }
|
||||
val expectedByModules = HashSet<ModuleInfo>()
|
||||
|
||||
while (unprocessedModules.isNotEmpty()) {
|
||||
val nextImplemented = unprocessedModules.removeFirst()
|
||||
if (expectedByModules.add(nextImplemented)) {
|
||||
unprocessedModules.addAll(nextImplemented.expectedBy)
|
||||
}
|
||||
}
|
||||
|
||||
return expectedByModules
|
||||
}
|
||||
|
||||
+11
-1
@@ -24,13 +24,23 @@ internal fun PropertyDescriptor.propertyKind(usageModule: ModuleDescriptor?): Da
|
||||
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||
if (!isInvisibleFromOtherModules()) {
|
||||
val declarationModule = DescriptorUtils.getContainingModule(this)
|
||||
if (usageModule == null || usageModule != declarationModule) {
|
||||
if (!areCompiledTogether(usageModule, declarationModule)) {
|
||||
return DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||
}
|
||||
}
|
||||
return DataFlowValue.Kind.STABLE_VALUE
|
||||
}
|
||||
|
||||
internal fun areCompiledTogether(
|
||||
usageModule: ModuleDescriptor?,
|
||||
declarationModule: ModuleDescriptor,
|
||||
): Boolean {
|
||||
if (usageModule == null) return false
|
||||
if (usageModule == declarationModule) return true
|
||||
|
||||
return declarationModule in usageModule.allExpectedByModules
|
||||
}
|
||||
|
||||
internal fun VariableDescriptor.variableKind(
|
||||
usageModule: ModuleDescriptor?,
|
||||
bindingContext: BindingContext,
|
||||
|
||||
Reference in New Issue
Block a user