[IC] Fixed IC for when expressions involving sealed interfaces

#KT-45474 Fixed
This commit is contained in:
Andrey Uskov
2022-06-10 16:39:26 +03:00
committed by teamcity
parent 7b8188d344
commit 21e762458e
3 changed files with 45 additions and 30 deletions
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import java.io.File
import java.util.*
import kotlin.collections.HashSet
/**
* Incremental cache common for JVM and JS, ClassName type aware
@@ -203,12 +204,34 @@ abstract class AbstractIncrementalCache<ClassName>(
override fun getComplementaryFilesRecursive(dirtyFiles: Collection<File>): Collection<File> {
val complementaryFiles = HashSet<File>()
val filesQueue = ArrayDeque(dirtyFiles)
val processedClasses = HashSet<FqName>()
val processedFiles = HashSet<File>()
while (filesQueue.isNotEmpty()) {
val file = filesQueue.pollFirst()
complementaryFilesMap[file].forEach {
if (complementaryFiles.add(it)) filesQueue.add(it)
if (processedFiles.contains(file)) {
continue
}
processedFiles.add(file)
complementaryFilesMap[file].forEach {
if (complementaryFiles.add(it) && !processedFiles.contains(it)) filesQueue.add(it)
}
val classes2recompile = sourceToClassesMap.getFqNames(file)
classes2recompile.filter { !processedClasses.contains(it) }.forEach {class2recompile ->
processedClasses.add(class2recompile)
val sealedClasses = findSealedSupertypes(class2recompile, listOf(this))
val allSubtypes = sealedClasses.flatMap { withSubtypes(it, listOf(this)) }.also {
// there could be only one sealed class in hierarchy
processedClasses.addAll(it)
}
val files2add = allSubtypes.mapNotNull { classFqNameToSourceMap[it] }.filter { !processedFiles.contains(it) }
filesQueue.addAll(files2add)
}
}
complementaryFiles.addAll(processedFiles)
complementaryFiles.removeAll(dirtyFiles)
return complementaryFiles
}
@@ -149,8 +149,7 @@ fun ChangesCollector.getDirtyData(
val dirtyLookupSymbols = HashSet<LookupSymbol>()
val dirtyClassesFqNames = HashSet<FqName>()
val sealedParents = HashMap<FqName, MutableSet<FqName>>()
val notSealedParents = HashSet<FqName>()
val sealedParents = HashSet<FqName>()
for (change in changes()) {
reporter.reportVerbose { "Process $change" }
@@ -177,34 +176,12 @@ fun ChangesCollector.getDirtyData(
fqNames.mapTo(dirtyLookupSymbols) { LookupSymbol(SAM_LOOKUP_NAME.asString(), it.asString()) }
} else if (change is ChangeInfo.ParentsChanged) {
fun FqName.isSealed(): Boolean {
if (notSealedParents.contains(this)) return false
if (sealedParents.containsKey(this)) return true
return isSealed(this, caches).also { sealed ->
if (sealed) {
sealedParents[this] = HashSet()
} else {
notSealedParents.add(this)
}
}
}
change.parentsChanged.forEach { parent ->
if (parent.isSealed()) {
sealedParents.getOrPut(parent) { HashSet() }.add(change.fqName)
}
sealedParents.addAll(findSealedSupertypes(parent, caches))
}
}
}
val forceRecompile = HashSet<FqName>().apply {
addAll(sealedParents.keys)
//we should recompile all inheritors with parent sealed class: add known subtypes
addAll(sealedParents.keys.flatMap { withSubtypes(it, caches) })
//we should recompile all inheritors with parent sealed class: add new subtypes
addAll(sealedParents.values.flatten())
}
return DirtyData(dirtyLookupSymbols, dirtyClassesFqNames, forceRecompile)
return DirtyData(dirtyLookupSymbols, dirtyClassesFqNames, sealedParents)
}
fun mapLookupSymbolsToFiles(
@@ -251,7 +228,22 @@ fun mapClassesFqNamesToFiles(
fun isSealed(
fqName: FqName,
caches: Iterable<IncrementalCacheCommon>
): Boolean = caches.any { it.isSealed(fqName) ?: false }
): Boolean = caches.any { cache -> cache.isSealed(fqName) ?: false }
/**
* Finds sealed supertypes of class in same module.
* This method should be used for processing freedomOsSealedClasses feature, because
* mutually declared list of sealed subclasses could be declared only in the same module.
*/
fun findSealedSupertypes(
fqName: FqName,
caches: Iterable<IncrementalCacheCommon>
): Collection<FqName> {
if (isSealed(fqName, caches)) {
return listOf(fqName)
}
return caches.flatMap { cache -> cache.getSupertypesOf(fqName).filter { cache.isSealed(it) ?: false }}
}
fun withSubtypes(
typeFqName: FqName,
@@ -281,7 +281,7 @@ object ClasspathChangesComputer {
val unmatchedLookupSymbols = dirtyData.dirtyLookupSymbols.toMutableSet().also {
it.removeAll(changes.lookupSymbols.toSet())
}
val unmatchedFqNames = (dirtyData.dirtyClassesFqNames + dirtyData.dirtyClassesFqNamesForceRecompile).toMutableSet().also {
val unmatchedFqNames = (dirtyData.dirtyClassesFqNames).toMutableSet().also {
it.removeAll(changes.fqNames.toSet())
}