[FE] Show causing types in the INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION diagnostic

This commit is contained in:
Victor Petukhov
2022-05-25 18:14:19 +02:00
committed by teamcity
parent 6a34b184ac
commit 867ad24c86
51 changed files with 217 additions and 163 deletions
@@ -10,7 +10,7 @@ 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.resolve.checkers.EmptyIntersectionTypeInfo
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
@@ -27,7 +27,7 @@ interface NewConstraintSystem {
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzerContext
fun processForkConstraints()
fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeKind
fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeInfo?
}
typealias ForkPointData = List<ConstraintsFromSingleFork>
@@ -137,19 +137,22 @@ class ConstrainingTypeIsError(
class NoSuccessfulFork(val position: IncorporationConstraintPosition) : ConstraintSystemError(INAPPLICABLE)
sealed interface InferredEmptyIntersection {
val incompatibleTypes: Collection<KotlinTypeMarker>
val incompatibleTypes: List<KotlinTypeMarker>
val causingTypes: List<KotlinTypeMarker>
val typeVariable: TypeVariableMarker
val kind: EmptyIntersectionTypeKind
}
class InferredEmptyIntersectionWarning(
override val incompatibleTypes: Collection<KotlinTypeMarker>,
override val incompatibleTypes: List<KotlinTypeMarker>,
override val causingTypes: List<KotlinTypeMarker>,
override val typeVariable: TypeVariableMarker,
override val kind: EmptyIntersectionTypeKind,
) : ConstraintSystemError(RESOLVED), InferredEmptyIntersection
class InferredEmptyIntersectionError(
override val incompatibleTypes: Collection<KotlinTypeMarker>,
override val incompatibleTypes: List<KotlinTypeMarker>,
override val causingTypes: List<KotlinTypeMarker>,
override val typeVariable: TypeVariableMarker,
override val kind: EmptyIntersectionTypeKind,
) : ConstraintSystemError(INAPPLICABLE), InferredEmptyIntersection
@@ -10,6 +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.resolve.checkers.EmptyIntersectionTypeInfo
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.SmartList
@@ -38,7 +39,7 @@ class NewConstraintSystemImpl(
private val typeVariablesTransaction: MutableList<TypeVariableMarker> = SmartList()
private val properTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
private val notProperTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
private val intersectionTypesCache: MutableMap<Collection<KotlinTypeMarker>, EmptyIntersectionTypeKind> = mutableMapOf()
private val intersectionTypesCache: MutableMap<Collection<KotlinTypeMarker>, EmptyIntersectionTypeInfo?> = mutableMapOf()
private var couldBeResolvedWithUnrestrictedBuilderInference: Boolean = false
override var atCompletionState: Boolean = false
@@ -441,7 +442,7 @@ class NewConstraintSystemImpl(
doPostponedComputationsIfAllVariablesAreFixed()
}
override fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeKind {
override fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeInfo? {
if (types in intersectionTypesCache)
return intersectionTypesCache.getValue(types)
@@ -458,18 +459,20 @@ class NewConstraintSystemImpl(
if (upperTypes.size <= 1 || storage.errors.any { it is InferredEmptyIntersection && it.incompatibleTypes == upperTypes })
return
val emptyIntersectionKind = getEmptyIntersectionTypeKind(upperTypes).takeIf { it.isEmpty() } ?: return
val emptyIntersectionTypeInfo = getEmptyIntersectionTypeKind(upperTypes) ?: return
// Remove existing errors from the resolution stage because a completion stage error is always more precise
storage.errors.removeIf { it is InferredEmptyIntersection }
val isInferredEmptyIntersectionForbidden =
languageVersionSettings.supportsFeature(LanguageFeature.ForbidInferringTypeVariablesIntoEmptyIntersection)
val errorFactory = if (emptyIntersectionKind.isDefinitelyEmpty() && isInferredEmptyIntersectionForbidden)
val errorFactory = if (emptyIntersectionTypeInfo.kind.isDefinitelyEmpty() && isInferredEmptyIntersectionForbidden)
::InferredEmptyIntersectionError
else ::InferredEmptyIntersectionWarning
addError(errorFactory(upperTypes, variable, emptyIntersectionKind))
addError(
errorFactory(upperTypes.toList(), emptyIntersectionTypeInfo.casingTypes.toList(), variable, emptyIntersectionTypeInfo.kind)
)
}
private fun checkMissedConstraints() {