[IC] Fixed IC for when expressions involving sealed interfaces
#KT-45474 Fixed
This commit is contained in:
@@ -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,
|
||||
|
||||
+1
-1
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user