Add equality constraints without subtyping
^KT-42195 Fixed ^KT-41741 Fixed
This commit is contained in:
+2
@@ -34,6 +34,8 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
|
||||
isFromNullabilityConstraint: Boolean = false
|
||||
)
|
||||
|
||||
abstract fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker)
|
||||
|
||||
override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy {
|
||||
return when {
|
||||
isMyTypeVariable(subType) -> {
|
||||
|
||||
+6
-2
@@ -40,15 +40,19 @@ class ConstraintIncorporator(
|
||||
fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext)
|
||||
}
|
||||
|
||||
fun incorporateIntoOtherConstraints(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
|
||||
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 incorporate(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
|
||||
fun incorporateSubtypeConstraint(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
|
||||
// we shouldn't incorporate recursive constraint -- It is too dangerous
|
||||
if (c.areThereRecursiveConstraints(typeVariable, constraint)) return
|
||||
|
||||
|
||||
+54
-15
@@ -39,28 +39,42 @@ class ConstraintInjector(
|
||||
|
||||
fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) {
|
||||
val initialConstraint = InitialConstraint(lowerType, upperType, UPPER, position).also { c.addInitialConstraint(it) }
|
||||
val typeCheckerContext = TypeCheckerContext(c, IncorporationConstraintPosition(position, initialConstraint))
|
||||
|
||||
updateAllowedTypeDepth(c, lowerType)
|
||||
updateAllowedTypeDepth(c, upperType)
|
||||
|
||||
addSubTypeConstraintAndIncorporateIt(
|
||||
c,
|
||||
lowerType,
|
||||
upperType,
|
||||
TypeCheckerContext(c, IncorporationConstraintPosition(position, initialConstraint))
|
||||
)
|
||||
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, typeCheckerContext)
|
||||
}
|
||||
|
||||
fun addInitialEqualityConstraint(c: Context, a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition) {
|
||||
val initialConstraint = InitialConstraint(a, b, EQUALITY, position).also { c.addInitialConstraint(it) }
|
||||
|
||||
updateAllowedTypeDepth(c, a)
|
||||
updateAllowedTypeDepth(c, b)
|
||||
private fun Context.addInitialEqualityConstraintThroughSubtyping(
|
||||
a: KotlinTypeMarker,
|
||||
b: KotlinTypeMarker,
|
||||
typeCheckerContext: TypeCheckerContext
|
||||
) {
|
||||
updateAllowedTypeDepth(this, a)
|
||||
updateAllowedTypeDepth(this, b)
|
||||
addSubTypeConstraintAndIncorporateIt(this, a, b, typeCheckerContext)
|
||||
addSubTypeConstraintAndIncorporateIt(this, b, a, typeCheckerContext)
|
||||
}
|
||||
|
||||
fun addInitialEqualityConstraint(c: Context, a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition) = with(c) {
|
||||
val (typeVariable, equalType) = when {
|
||||
a.typeConstructor(c) is TypeVariableTypeConstructorMarker -> a to b
|
||||
b.typeConstructor(c) is TypeVariableTypeConstructorMarker -> b to a
|
||||
else -> return
|
||||
}
|
||||
val initialConstraint = InitialConstraint(typeVariable, equalType, EQUALITY, position).also { c.addInitialConstraint(it) }
|
||||
val typeCheckerContext = TypeCheckerContext(c, IncorporationConstraintPosition(position, initialConstraint))
|
||||
|
||||
addSubTypeConstraintAndIncorporateIt(c, a, b, typeCheckerContext)
|
||||
addSubTypeConstraintAndIncorporateIt(c, b, a, typeCheckerContext)
|
||||
// We add constraints like `T? == Foo!` in the old way
|
||||
if (!typeVariable.isSimpleType() || typeVariable.isMarkedNullable()) {
|
||||
addInitialEqualityConstraintThroughSubtyping(typeVariable, equalType, typeCheckerContext)
|
||||
return
|
||||
}
|
||||
|
||||
updateAllowedTypeDepth(c, equalType)
|
||||
addEqualityConstraintAndIncorporateIt(c, typeVariable, equalType, typeCheckerContext)
|
||||
}
|
||||
|
||||
private fun addSubTypeConstraintAndIncorporateIt(
|
||||
@@ -72,6 +86,26 @@ class ConstraintInjector(
|
||||
typeCheckerContext.setConstrainingTypesToPrintDebugInfo(lowerType, upperType)
|
||||
typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
|
||||
|
||||
processConstraints(c, typeCheckerContext, constraintIncorporator::incorporateSubtypeConstraint)
|
||||
}
|
||||
|
||||
private fun addEqualityConstraintAndIncorporateIt(
|
||||
c: Context,
|
||||
typeVariable: KotlinTypeMarker,
|
||||
equalType: KotlinTypeMarker,
|
||||
typeCheckerContext: TypeCheckerContext
|
||||
) {
|
||||
typeCheckerContext.setConstrainingTypesToPrintDebugInfo(typeVariable, equalType)
|
||||
typeCheckerContext.addEqualityConstraint(typeVariable.typeConstructor(c), equalType)
|
||||
|
||||
processConstraints(c, typeCheckerContext, constraintIncorporator::incorporateEqualityConstraint)
|
||||
}
|
||||
|
||||
private fun processConstraints(
|
||||
c: Context,
|
||||
typeCheckerContext: TypeCheckerContext,
|
||||
incorporate: (c: TypeCheckerContext, typeVariable: TypeVariableMarker, constraint: Constraint) -> Unit
|
||||
) {
|
||||
while (typeCheckerContext.hasConstraintsToProcess()) {
|
||||
for ((typeVariable, constraint) in typeCheckerContext.extractAllConstraints()!!) {
|
||||
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
|
||||
@@ -82,7 +116,7 @@ class ConstraintInjector(
|
||||
// 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)
|
||||
incorporate(typeCheckerContext, typeVariable, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +139,8 @@ class ConstraintInjector(
|
||||
}
|
||||
|
||||
private fun Context.shouldWeSkipConstraint(typeVariable: TypeVariableMarker, constraint: Constraint): Boolean {
|
||||
assert(constraint.kind != EQUALITY)
|
||||
if (constraint.kind == EQUALITY)
|
||||
return false
|
||||
|
||||
val constraintType = constraint.type
|
||||
|
||||
@@ -221,6 +256,10 @@ class ConstraintInjector(
|
||||
isFromNullabilityConstraint: Boolean
|
||||
) = addConstraint(typeVariable, subType, LOWER, isFromNullabilityConstraint)
|
||||
|
||||
override fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker) {
|
||||
addConstraint(typeVariable, type, EQUALITY, false)
|
||||
}
|
||||
|
||||
private fun isCapturedTypeFromSubtyping(type: KotlinTypeMarker) =
|
||||
when ((type as? CapturedTypeMarker)?.captureStatus()) {
|
||||
null, CaptureStatus.FROM_EXPRESSION -> false
|
||||
|
||||
Reference in New Issue
Block a user