NI: small refactoring around TypeCheckerContext and adding new possible constraints

This commit is contained in:
Victor Petukhov
2020-05-27 12:19:02 +03:00
parent d7f52e8b67
commit 0bed055fca
2 changed files with 65 additions and 51 deletions
@@ -38,22 +38,26 @@ class ConstraintIncorporator(
fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext) fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext)
} }
fun incorporateIntoOtherConstraints(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) = fun incorporateIntoOtherConstraints(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
// we shouldn't incorporate recursive constraint -- It is too dangerous
if (c.areThereRecursiveConstraints(typeVariable, constraint)) return
c.insideOtherConstraint(typeVariable, constraint) c.insideOtherConstraint(typeVariable, constraint)
}
// \alpha is typeVariable, \beta -- other type variable registered in ConstraintStorage // \alpha is typeVariable, \beta -- other type variable registered in ConstraintStorage
fun incorporate(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) { fun incorporate(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
// we shouldn't incorporate recursive constraint -- It is too dangerous // we shouldn't incorporate recursive constraint -- It is too dangerous
with(c) { if (c.areThereRecursiveConstraints(typeVariable, constraint)) return
val freshTypeConstructor = typeVariable.freshTypeConstructor()
if (constraint.type.contains { it.typeConstructor() == freshTypeConstructor }) return
}
c.directWithVariable(typeVariable, constraint) c.directWithVariable(typeVariable, constraint)
c.otherInsideMyConstraint(typeVariable, constraint) c.otherInsideMyConstraint(typeVariable, constraint)
c.insideOtherConstraint(typeVariable, constraint) c.insideOtherConstraint(typeVariable, constraint)
} }
private fun Context.areThereRecursiveConstraints(typeVariable: TypeVariableMarker, constraint: Constraint) =
constraint.type.contains { it.typeConstructor() == typeVariable.freshTypeConstructor() }
// A <:(=) \alpha <:(=) B => A <: B // A <:(=) \alpha <:(=) B => A <: B
private fun Context.directWithVariable( private fun Context.directWithVariable(
typeVariable: TypeVariableMarker, typeVariable: TypeVariableMarker,
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.jetbrains.kotlin.utils.SmartList
import kotlin.math.max import kotlin.math.max
class ConstraintInjector( class ConstraintInjector(
@@ -47,47 +46,51 @@ class ConstraintInjector(
} }
fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) { fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) {
val initialConstraint = InitialConstraint(lowerType, upperType, UPPER, position) val initialConstraint = InitialConstraint(lowerType, upperType, UPPER, position).also { c.addInitialConstraint(it) }
c.addInitialConstraint(initialConstraint)
updateAllowedTypeDepth(c, lowerType) updateAllowedTypeDepth(c, lowerType)
updateAllowedTypeDepth(c, upperType) updateAllowedTypeDepth(c, upperType)
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, IncorporationConstraintPosition(position, initialConstraint))
addSubTypeConstraintAndIncorporateIt(
c,
lowerType,
upperType,
TypeCheckerContext(c, IncorporationConstraintPosition(position, initialConstraint))
)
} }
fun addInitialEqualityConstraint(c: Context, a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition) { fun addInitialEqualityConstraint(c: Context, a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition) {
val initialConstraint = InitialConstraint(a, b, EQUALITY, position) val initialConstraint = InitialConstraint(a, b, EQUALITY, position).also { c.addInitialConstraint(it) }
c.addInitialConstraint(initialConstraint)
updateAllowedTypeDepth(c, a) updateAllowedTypeDepth(c, a)
updateAllowedTypeDepth(c, b) updateAllowedTypeDepth(c, b)
addSubTypeConstraintAndIncorporateIt(c, a, b, IncorporationConstraintPosition(position, initialConstraint))
addSubTypeConstraintAndIncorporateIt(c, b, a, IncorporationConstraintPosition(position, initialConstraint)) val incorporationConstraintPosition = IncorporationConstraintPosition(position, initialConstraint)
val typeCheckerContext = TypeCheckerContext(c, incorporationConstraintPosition)
if (position is FixVariableConstraintPosition) {
c.incorporateEqualityConstraintForFixingTypeVariable(
incorporationConstraintPosition, position.variable, resultType = b, typeCheckerContext
)
}
addSubTypeConstraintAndIncorporateIt(c, a, b, typeCheckerContext)
addSubTypeConstraintAndIncorporateIt(c, b, a, typeCheckerContext)
} }
private fun addSubTypeConstraintAndIncorporateIt( private fun addSubTypeConstraintAndIncorporateIt(
c: Context, c: Context,
lowerType: KotlinTypeMarker, lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker, upperType: KotlinTypeMarker,
incorporatePosition: IncorporationConstraintPosition typeCheckerContext: TypeCheckerContext
) { ) {
var possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>? = null typeCheckerContext.setConstrainingTypesToPrintDebugInfo(lowerType, upperType)
val typeCheckerContext = TypeCheckerContext(c, incorporatePosition, lowerType, upperType) { typeVar, constraint ->
if (possibleNewConstraints == null) {
possibleNewConstraints = SmartList()
}
possibleNewConstraints!!.add(typeVar to constraint)
}
typeCheckerContext.runIsSubtypeOf(lowerType, upperType) typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
var constraintsFromIsSubtype = true var constraintsFromIsSubtype = true
if (incorporatePosition.from is FixVariableConstraintPosition && lowerType == incorporatePosition.initialConstraint.a) { while (typeCheckerContext.hasConstraintsToProcess()) {
c.incorporateEqualityConstraintForFixingTypeVariable(incorporatePosition, typeCheckerContext) for ((typeVariable, constraint) in typeCheckerContext.extractAllConstraints()) {
}
while (possibleNewConstraints != null) {
val constraintsToProcess = possibleNewConstraints
possibleNewConstraints = null
for ((typeVariable, constraint) in constraintsToProcess!!) {
if (c.shouldWeSkipConstraint(typeVariable, constraint, constraintsFromIsSubtype)) continue if (c.shouldWeSkipConstraint(typeVariable, constraint, constraintsFromIsSubtype)) continue
val constraints = val constraints =
@@ -102,7 +105,7 @@ class ConstraintInjector(
} }
val contextOps = c as? ConstraintSystemOperation val contextOps = c as? ConstraintSystemOperation
if (possibleNewConstraints == null || if (!typeCheckerContext.hasConstraintsToProcess() ||
(contextOps != null && c.notFixedTypeVariables.all { typeVariable -> (contextOps != null && c.notFixedTypeVariables.all { typeVariable ->
typeVariable.value.constraints.any { constraint -> typeVariable.value.constraints.any { constraint ->
constraint.kind == EQUALITY && contextOps.isProperType(constraint.type) constraint.kind == EQUALITY && contextOps.isProperType(constraint.type)
@@ -121,24 +124,18 @@ class ConstraintInjector(
private fun Context.incorporateEqualityConstraintForFixingTypeVariable( private fun Context.incorporateEqualityConstraintForFixingTypeVariable(
incorporatePosition: IncorporationConstraintPosition, incorporatePosition: IncorporationConstraintPosition,
fixingTypeVariable: TypeVariableMarker,
resultType: KotlinTypeMarker,
typeCheckerContext: TypeCheckerContext typeCheckerContext: TypeCheckerContext
) { ) {
if (incorporatePosition.from !is FixVariableConstraintPosition) return if (resultType.isUninferredParameter() || resultType.isError()) return
val typeToIncorporate = incorporatePosition.initialConstraint.b assert(!resultType.contains { it.typeConstructor() is TypeVariableTypeConstructor })
if (typeToIncorporate.isUninferredParameter() || typeToIncorporate.isError()) return
constraintIncorporator.incorporateIntoOtherConstraints( constraintIncorporator.incorporateIntoOtherConstraints(
typeCheckerContext, typeCheckerContext,
incorporatePosition.from.variable, fixingTypeVariable,
Constraint( Constraint(EQUALITY, resultType, incorporatePosition, derivedFrom = emptySet(), isNullabilityConstraint = false)
EQUALITY,
typeToIncorporate,
incorporatePosition,
derivedFrom = setOf(),
isNullabilityConstraint = false
)
) )
} }
@@ -172,13 +169,25 @@ class ConstraintInjector(
private fun Context.isAllowedType(type: KotlinTypeMarker) = private fun Context.isAllowedType(type: KotlinTypeMarker) =
type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
private inner class TypeCheckerContext( private inner class TypeCheckerContext(val c: Context, val position: IncorporationConstraintPosition) :
val c: Context, AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c {
val position: IncorporationConstraintPosition, private val newPossibleConstraints = mutableSetOf<Pair<TypeVariableMarker, Constraint>>()
val baseLowerType: KotlinTypeMarker,
val baseUpperType: KotlinTypeMarker, private var baseLowerType = position.initialConstraint.a
val addPossibleNewConstraints: (TypeVariableMarker, Constraint) -> Unit private var baseUpperType = position.initialConstraint.b
) : AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c {
fun extractAllConstraints(): Set<Pair<TypeVariableMarker, Constraint>> {
val newConstraintsSet = newPossibleConstraints.toSet()
newPossibleConstraints.clear()
return newConstraintsSet
}
fun hasConstraintsToProcess() = newPossibleConstraints.isNotEmpty()
fun setConstrainingTypesToPrintDebugInfo(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) {
baseLowerType = lowerType
baseUpperType = upperType
}
val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything, isStubTypeEqualsToAnything) val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything, isStubTypeEqualsToAnything)
@@ -333,7 +342,8 @@ class ConstraintInjector(
isNullabilityConstraint = isNullabilityConstraint, isNullabilityConstraint = isNullabilityConstraint,
inputTypePositionBeforeIncorporation = inputTypePosition inputTypePositionBeforeIncorporation = inputTypePosition
) )
addPossibleNewConstraints(typeVariable, newConstraint)
newPossibleConstraints.add(typeVariable to newConstraint)
} }
override val allTypeVariablesWithConstraints: Collection<VariableWithConstraints> override val allTypeVariablesWithConstraints: Collection<VariableWithConstraints>