[FE] Cache checking intersection type emptiness results

This commit is contained in:
Victor Petukhov
2022-05-05 18:23:29 +02:00
committed by teamcity
parent 9a3b5e547b
commit e133ee3765
4 changed files with 27 additions and 8 deletions
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemC
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError
import org.jetbrains.kotlin.types.EmptyIntersectionTypeKind
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
interface NewConstraintSystem {
@@ -24,6 +26,8 @@ interface NewConstraintSystem {
fun asConstraintSystemCompleterContext(): ConstraintSystemCompletionContext
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzerContext
fun processForkConstraints()
fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeKind
}
typealias ForkPointData = List<ConstraintsFromSingleFork>
@@ -10,10 +10,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzerContext
import org.jetbrains.kotlin.resolve.calls.inference.*
import org.jetbrains.kotlin.resolve.calls.inference.components.*
import org.jetbrains.kotlin.types.AbstractTypeApproximator
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.isDefinitelyEmpty
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.SmartSet
@@ -41,6 +38,8 @@ class NewConstraintSystemImpl(
private val typeVariablesTransaction: MutableList<TypeVariableMarker> = SmartList()
private val properTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
private val notProperTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
private val emptyIntersectionTypesCache: MutableSet<Collection<KotlinTypeMarker>> = SmartSet.create()
private val nonEmptyIntersectionTypesCache: MutableSet<Collection<KotlinTypeMarker>> = SmartSet.create()
private var couldBeResolvedWithUnrestrictedBuilderInference: Boolean = false
@@ -444,6 +443,21 @@ class NewConstraintSystemImpl(
doPostponedComputationsIfAllVariablesAreFixed()
}
override fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeKind {
if (types in emptyIntersectionTypesCache)
return EmptyIntersectionTypeKind.MULTIPLE_CLASSES
if (types in nonEmptyIntersectionTypesCache)
return EmptyIntersectionTypeKind.NOT_EMPTY_INTERSECTION
return types.computeEmptyIntersectionTypeKind().also {
when (it) {
EmptyIntersectionTypeKind.MULTIPLE_CLASSES -> emptyIntersectionTypesCache.add(types)
EmptyIntersectionTypeKind.NOT_EMPTY_INTERSECTION -> nonEmptyIntersectionTypesCache.add(types)
}
}
}
private fun checkInferredEmptyIntersection(variable: TypeVariableMarker, resultType: KotlinTypeMarker) {
val intersectionTypeConstructor = resultType.typeConstructor().takeIf { it is IntersectionTypeConstructorMarker } ?: return
val isInferredEmptyIntersectionForbidden =
@@ -454,7 +468,7 @@ class NewConstraintSystemImpl(
if (upperTypes.size <= 1 || storage.errors.any { it is InferredEmptyIntersection && it.incompatibleTypes == upperTypes })
return
if (upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty()) {
if (getEmptyIntersectionTypeKind(upperTypes).isDefinitelyEmpty()) {
// Remove existing errors from resolution stage because a completion error is more precise
storage.errors.removeIf { it is InferredEmptyIntersection }
val errorFactory =