Rethink constraints incorporation
Namely, remove incorporation “otherInsideMyConstraint” to eliminate constraint system redundancy and produce a potentially very large number of constructs. Instead, introduce not so “spreadable” incorporation during variable fixation (equality constraint with result type into other constraints). ^KT-41644 Fixed ^KT-42195 Fixed ^KT-42920 Fixed ^KT-42791 Fixed ^KT-41741 Fixed
This commit is contained in:
+1
-33
@@ -40,24 +40,12 @@ class ConstraintIncorporator(
|
||||
fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext)
|
||||
}
|
||||
|
||||
fun incorporateEqualityConstraint(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) = with(c) {
|
||||
// we shouldn't incorporate recursive constraint -- It is too dangerous
|
||||
if (c.areThereRecursiveConstraints(typeVariable, constraint)) return
|
||||
|
||||
c.directWithVariable(typeVariable, constraint)
|
||||
if (constraint.type.contains { it is TypeVariableTypeConstructorMarker }) {
|
||||
c.otherInsideMyConstraint(typeVariable, constraint)
|
||||
}
|
||||
c.insideOtherConstraint(typeVariable, constraint)
|
||||
}
|
||||
|
||||
// \alpha is typeVariable, \beta -- other type variable registered in ConstraintStorage
|
||||
fun incorporateSubtypeConstraint(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
|
||||
fun incorporate(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
|
||||
// we shouldn't incorporate recursive constraint -- It is too dangerous
|
||||
if (c.areThereRecursiveConstraints(typeVariable, constraint)) return
|
||||
|
||||
c.directWithVariable(typeVariable, constraint)
|
||||
c.otherInsideMyConstraint(typeVariable, constraint)
|
||||
c.insideOtherConstraint(typeVariable, constraint)
|
||||
}
|
||||
|
||||
@@ -98,26 +86,6 @@ class ConstraintIncorporator(
|
||||
}
|
||||
}
|
||||
|
||||
// \alpha <: Inv<\beta>, \beta <: Number => \alpha <: Inv<out Number>
|
||||
private fun Context.otherInsideMyConstraint(
|
||||
typeVariable: TypeVariableMarker,
|
||||
constraint: Constraint
|
||||
) {
|
||||
val otherInMyConstraint = SmartSet.create<TypeVariableMarker>()
|
||||
constraint.type.contains {
|
||||
otherInMyConstraint.addIfNotNull(this.getTypeVariable(it.typeConstructor()))
|
||||
false
|
||||
}
|
||||
|
||||
for (otherTypeVariable in otherInMyConstraint) {
|
||||
// to avoid ConcurrentModificationException
|
||||
val otherConstraints = SmartList(this.getConstraintsForVariable(otherTypeVariable))
|
||||
for (otherConstraint in otherConstraints) {
|
||||
generateNewConstraint(typeVariable, constraint, otherTypeVariable, otherConstraint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// \alpha <: Number, \beta <: Inv<\alpha> => \beta <: Inv<out Number>
|
||||
private fun Context.insideOtherConstraint(
|
||||
typeVariable: TypeVariableMarker,
|
||||
|
||||
+15
-13
@@ -85,7 +85,7 @@ class ConstraintInjector(
|
||||
typeCheckerContext.setConstrainingTypesToPrintDebugInfo(lowerType, upperType)
|
||||
typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
|
||||
|
||||
processConstraints(c, typeCheckerContext, constraintIncorporator::incorporateSubtypeConstraint)
|
||||
processConstraints(c, typeCheckerContext)
|
||||
}
|
||||
|
||||
private fun addEqualityConstraintAndIncorporateIt(
|
||||
@@ -97,14 +97,10 @@ class ConstraintInjector(
|
||||
typeCheckerContext.setConstrainingTypesToPrintDebugInfo(typeVariable, equalType)
|
||||
typeCheckerContext.addEqualityConstraint(typeVariable.typeConstructor(c), equalType)
|
||||
|
||||
processConstraints(c, typeCheckerContext, constraintIncorporator::incorporateEqualityConstraint)
|
||||
processConstraints(c, typeCheckerContext)
|
||||
}
|
||||
|
||||
private fun processConstraints(
|
||||
c: Context,
|
||||
typeCheckerContext: TypeCheckerContext,
|
||||
incorporate: (c: TypeCheckerContext, typeVariable: TypeVariableMarker, constraint: Constraint) -> Unit
|
||||
) {
|
||||
private fun processConstraints(c: Context, typeCheckerContext: TypeCheckerContext) {
|
||||
while (typeCheckerContext.hasConstraintsToProcess()) {
|
||||
for ((typeVariable, constraint) in typeCheckerContext.extractAllConstraints()!!) {
|
||||
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
|
||||
@@ -113,10 +109,17 @@ class ConstraintInjector(
|
||||
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) {
|
||||
incorporate(typeCheckerContext, typeVariable, it)
|
||||
}
|
||||
val (addedOrNonRedundantExistedConstraint, wasAdded) = constraints.addConstraint(constraint)
|
||||
val positionFrom = constraint.position.from
|
||||
val constraintToIncorporate = when {
|
||||
wasAdded && !constraint.isNullabilityConstraint -> addedOrNonRedundantExistedConstraint
|
||||
positionFrom is FixVariableConstraintPosition<*> && positionFrom.variable == typeVariable && constraint.kind == EQUALITY ->
|
||||
addedOrNonRedundantExistedConstraint
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (constraintToIncorporate != null) {
|
||||
constraintIncorporator.incorporate(typeCheckerContext, typeVariable, constraintToIncorporate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,9 +258,8 @@ class ConstraintInjector(
|
||||
isFromNullabilityConstraint: Boolean
|
||||
) = addConstraint(typeVariable, subType, LOWER, isFromNullabilityConstraint)
|
||||
|
||||
override fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker) {
|
||||
override fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker) =
|
||||
addConstraint(typeVariable, type, EQUALITY, false)
|
||||
}
|
||||
|
||||
private fun isCapturedTypeFromSubtyping(type: KotlinTypeMarker) =
|
||||
when ((type as? CapturedTypeMarker)?.captureStatus()) {
|
||||
|
||||
+10
-6
@@ -47,8 +47,9 @@ class MutableVariableWithConstraints private constructor(
|
||||
|
||||
private var simplifiedConstraints: SmartList<Constraint>? = mutableConstraints
|
||||
|
||||
// return new actual constraint, if this constraint is new
|
||||
fun addConstraint(constraint: Constraint): Constraint? {
|
||||
// return new actual constraint, if this constraint is new, otherwise return already existed not redundant constraint
|
||||
// the second element of pair is a flag whether a constraint was added in fact
|
||||
fun addConstraint(constraint: Constraint): Pair<Constraint, Boolean> {
|
||||
val isLowerAndFlexibleTypeWithDefNotNullLowerBound = constraint.isLowerAndFlexibleTypeWithDefNotNullLowerBound()
|
||||
|
||||
for (previousConstraint in constraints) {
|
||||
@@ -56,7 +57,10 @@ class MutableVariableWithConstraints private constructor(
|
||||
&& previousConstraint.type == constraint.type
|
||||
&& previousConstraint.isNullabilityConstraint == constraint.isNullabilityConstraint
|
||||
) {
|
||||
if (newConstraintIsUseless(previousConstraint, constraint)) return null
|
||||
if (newConstraintIsUseless(previousConstraint, constraint)) {
|
||||
return previousConstraint to false
|
||||
}
|
||||
|
||||
val isMatchingForSimplification = when (previousConstraint.kind) {
|
||||
ConstraintKind.LOWER -> constraint.kind.isUpper()
|
||||
ConstraintKind.UPPER -> constraint.kind.isLower()
|
||||
@@ -75,14 +79,14 @@ class MutableVariableWithConstraints private constructor(
|
||||
} else constraint
|
||||
mutableConstraints.add(actualConstraint)
|
||||
simplifiedConstraints = null
|
||||
return actualConstraint
|
||||
return actualConstraint to true
|
||||
}
|
||||
}
|
||||
|
||||
if (isLowerAndFlexibleTypeWithDefNotNullLowerBound &&
|
||||
previousConstraint.isStrongerThanLowerAndFlexibleTypeWithDefNotNullLowerBound(constraint)
|
||||
) {
|
||||
return null
|
||||
return previousConstraint to false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +99,7 @@ class MutableVariableWithConstraints private constructor(
|
||||
simplifiedConstraints = null
|
||||
}
|
||||
|
||||
return constraint
|
||||
return constraint to true
|
||||
}
|
||||
|
||||
// This method should be used only for transaction in constraint system
|
||||
|
||||
Reference in New Issue
Block a user