[FE] Cache checking intersection type emptiness results
This commit is contained in:
committed by
teamcity
parent
9a3b5e547b
commit
e133ee3765
@@ -584,7 +584,7 @@ internal object CheckIncompatibleTypeVariableUpperBounds : ResolutionStage() {
|
||||
if (upperTypes.size <= 1 || variableWithConstraints.constraints.any { it.kind.isLower() })
|
||||
continue
|
||||
|
||||
if (upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty()) {
|
||||
if (candidate.system.getEmptyIntersectionTypeKind(upperTypes).isDefinitelyEmpty()) {
|
||||
sink.yieldDiagnostic(
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
InferredEmptyIntersectionDiagnostic(
|
||||
|
||||
+4
@@ -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>
|
||||
|
||||
+19
-5
@@ -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 =
|
||||
|
||||
+3
-2
@@ -889,7 +889,8 @@ internal object CheckIncompatibleTypeVariableUpperBounds : ResolutionPart() {
|
||||
callComponents.statelessCallbacks.isOldIntersectionIsEmpty(upperTypes.cast())
|
||||
|
||||
override fun ResolutionCandidate.process(workIndex: Int) = with(getSystem().asConstraintSystemCompleterContext()) {
|
||||
for (variableWithConstraints in getSystem().getBuilder().currentStorage().notFixedTypeVariables.values) {
|
||||
val constraintSystem = getSystem()
|
||||
for (variableWithConstraints in constraintSystem.getBuilder().currentStorage().notFixedTypeVariables.values) {
|
||||
val upperTypes = variableWithConstraints.constraints.extractUpperTypesToCheckIntersectionEmptiness()
|
||||
|
||||
when {
|
||||
@@ -900,7 +901,7 @@ internal object CheckIncompatibleTypeVariableUpperBounds : ResolutionPart() {
|
||||
markCandidateForCompatibilityResolve(needToReportWarning = false)
|
||||
continue
|
||||
}
|
||||
upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty() -> {
|
||||
constraintSystem.getEmptyIntersectionTypeKind(upperTypes).isDefinitelyEmpty() -> {
|
||||
val isInferredEmptyIntersectionForbidden =
|
||||
callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ForbidInferringTypeVariablesIntoEmptyIntersection)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user