Stop subtyping constraint search if equality constraints for...

all not fixed type vars are found
#KT-35626 fixed
This commit is contained in:
Ilya Chernikov
2020-02-21 16:39:52 +01:00
parent b6c9432334
commit 70c89a28e1
46 changed files with 211 additions and 63 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.LOWER
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.UPPER
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.max
class ConstraintInjector(
@@ -69,23 +71,38 @@ class ConstraintInjector(
upperType: KotlinTypeMarker,
incorporatePosition: IncorporationConstraintPosition
) {
val possibleNewConstraints = Stack<Pair<TypeVariableMarker, Constraint>>()
val possibleNewConstraints = ArrayList<Pair<TypeVariableMarker, Constraint>>()
val typeCheckerContext = TypeCheckerContext(c, incorporatePosition, lowerType, upperType, possibleNewConstraints)
typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
while (possibleNewConstraints.isNotEmpty()) {
val (typeVariable, constraint) = possibleNewConstraints.pop()
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
val constraints =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor(c)] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
val constraintsToProcess = possibleNewConstraints.toTypedArray()
possibleNewConstraints.clear()
for ((typeVariable, constraint) in constraintsToProcess) {
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
constraints.addConstraint(constraint)?.let {
if (!constraint.isNullabilityConstraint) {
constraintIncorporator.incorporate(typeCheckerContext, typeVariable, it)
val constraints =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor(c)] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
constraints.addConstraint(constraint)?.let {
if (!constraint.isNullabilityConstraint) {
constraintIncorporator.incorporate(typeCheckerContext, typeVariable, it)
}
}
}
val contextOps = c as? ConstraintSystemOperation
if (possibleNewConstraints == null ||
(contextOps != null && c.notFixedTypeVariables.all { typeVariable ->
typeVariable.value.constraints.any { constraint ->
constraint.kind == ConstraintKind.EQUALITY && contextOps.isProperType(constraint.type)
}
})
) {
break
}
}
}
@@ -122,7 +139,7 @@ class ConstraintInjector(
val position: IncorporationConstraintPosition,
val baseLowerType: KotlinTypeMarker,
val baseUpperType: KotlinTypeMarker,
val possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>
val possibleNewConstraints: MutableCollection<Pair<TypeVariableMarker, Constraint>>
) : AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c {
val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything, isStubTypeEqualsToAnything)