[NI] Support fixation to subtype in completion mode calculator

Allow full compltion mode for return type depending on type parameters in
contravariant position only if they have proper equality constraint.
This commit is contained in:
Pavel Kirpichenkov
2019-12-19 13:56:53 +03:00
parent e69e45e2a6
commit 384bd858e9
12 changed files with 178 additions and 13 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
import java.util.*
typealias CsCompleterContext = KotlinConstraintSystemCompleter.Context
@@ -45,10 +46,11 @@ class CompletionModeCalculator {
private val csCompleterContext: CsCompleterContext
) {
private enum class FixationDirection {
TO_SUBTYPE, TO_SUPERTYPE, EQUALITY
TO_SUBTYPE, EQUALITY
}
private val fixationDirectionsForVariables = mutableMapOf<VariableWithConstraints, FixationDirection>()
private val fixationDirectionsForVariables: MutableMap<VariableWithConstraints, FixationDirection> =
newLinkedHashMapWithExpectedSize(csCompleterContext.notFixedTypeVariables.size)
private val variablesWithQueuedConstraints = mutableSetOf<TypeVariableMarker>()
private val typesToProcess: Queue<KotlinTypeMarker> = ArrayDeque()
@@ -68,14 +70,14 @@ class CompletionModeCalculator {
while (typesToProcess.isNotEmpty()) {
val type = typesToProcess.poll() ?: break
fixationRequirementForTopLevel(type)?.let { directionForVariable ->
fixationDirectionForTopLevel(type)?.let { directionForVariable ->
updateDirection(directionForVariable)
enqueueTypesFromConstraints(directionForVariable.variable)
}
// find all variables in type and make requirements for them
type.contains { fromReturnType ->
for (directionForVariable in directionsForVariablesInTypeArguments(fromReturnType)) {
type.contains { typePart ->
for (directionForVariable in directionsForVariablesInTypeArguments(typePart)) {
updateDirection(directionForVariable)
enqueueTypesFromConstraints(directionForVariable.variable)
}
@@ -106,16 +108,16 @@ class CompletionModeCalculator {
private fun updateDirection(directionForVariable: FixationDirectionForVariable) {
val (variable, newDirection) = directionForVariable
fixationDirectionsForVariables[variable]?.let { oldDirection ->
// To sub and to super are merged into equality, old equality stays
if (oldDirection != FixationDirection.EQUALITY && oldDirection != newDirection)
fixationDirectionsForVariables[variable] = FixationDirection.EQUALITY
} ?: run {
fixationDirectionsForVariables[variable] = newDirection
}
fixationDirectionsForVariables[variable] = newDirection
}
private data class FixationDirectionForVariable(val variable: VariableWithConstraints, val direction: FixationDirection)
private fun CsCompleterContext.fixationRequirementForTopLevel(type: KotlinTypeMarker): FixationDirectionForVariable? {
private fun CsCompleterContext.fixationDirectionForTopLevel(type: KotlinTypeMarker): FixationDirectionForVariable? {
return notFixedTypeVariables[type.typeConstructor()]?.let {
FixationDirectionForVariable(it, FixationDirection.TO_SUBTYPE)
}
@@ -138,10 +140,10 @@ class CompletionModeCalculator {
val parameter = type.typeConstructor().getParameter(position)
val effectiveVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
?: TypeVariance.OUT // Discuss
?: TypeVariance.INV
val direction = when (effectiveVariance) {
TypeVariance.IN -> FixationDirection.TO_SUPERTYPE
TypeVariance.IN -> FixationDirection.EQUALITY // Assuming that variables in contravariant positions are fixed to subtype
TypeVariance.OUT -> FixationDirection.TO_SUBTYPE
TypeVariance.INV -> FixationDirection.EQUALITY
}
@@ -169,7 +171,6 @@ class CompletionModeCalculator {
private fun Constraint.hasRequiredKind(direction: FixationDirection) = when (direction) {
FixationDirection.TO_SUBTYPE -> kind.isLower() || kind.isEqual()
FixationDirection.TO_SUPERTYPE -> kind.isUpper() || kind.isEqual()
FixationDirection.EQUALITY -> kind.isEqual()
}
}