NI: propagate isNullabilityConstraint flag into constraint injector and inherit it

^KT-37510 Fixed
This commit is contained in:
Victor Petukhov
2020-04-07 13:50:50 +03:00
parent 19e352a1b5
commit 11d05c1abd
11 changed files with 142 additions and 26 deletions
@@ -28,7 +28,11 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
// super and sub type isSingleClassifierType
abstract fun addUpperConstraint(typeVariable: TypeConstructorMarker, superType: KotlinTypeMarker)
abstract fun addLowerConstraint(typeVariable: TypeConstructorMarker, subType: KotlinTypeMarker)
abstract fun addLowerConstraint(
typeVariable: TypeConstructorMarker,
subType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean = false
)
override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy {
return when {
@@ -52,7 +56,11 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
* then we can get wrong result.
* override val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.TAKE_FIRST_FOR_SUBTYPING
*/
final override fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
final override fun addSubtypeConstraint(
subType: KotlinTypeMarker,
superType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean
): Boolean? {
val hasNoInfer = subType.isTypeVariableWithNoInfer() || superType.isTypeVariableWithNoInfer()
if (hasNoInfer) return true
@@ -64,10 +72,10 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
val mySuperType =
if (hasExact) extractTypeForProjectedType(superType, out = false) ?: superType.removeExactAnnotation() else superType
val result = internalAddSubtypeConstraint(mySubType, mySuperType)
val result = internalAddSubtypeConstraint(mySubType, mySuperType, isFromNullabilityConstraint)
if (!hasExact) return result
val result2 = internalAddSubtypeConstraint(mySuperType, mySubType)
val result2 = internalAddSubtypeConstraint(mySuperType, mySubType, isFromNullabilityConstraint)
if (result == null && result2 == null) return null
return (result ?: true) && (result2 ?: true)
@@ -93,13 +101,17 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
private fun KotlinTypeMarker.isTypeVariableWithNoInfer() =
hasNoInferAnnotation() && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable)
private fun internalAddSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
private fun internalAddSubtypeConstraint(
subType: KotlinTypeMarker,
superType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean
): Boolean? {
assertInputTypes(subType, superType)
var answer: Boolean? = null
if (superType.anyBound(this::isMyTypeVariable)) {
answer = simplifyLowerConstraint(superType, subType)
answer = simplifyLowerConstraint(superType, subType, isFromNullabilityConstraint)
}
if (subType.anyBound(this::isMyTypeVariable)) {
@@ -178,7 +190,11 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
*
* => (Foo..Bar) <: T! -- (Foo!! .. Bar) <: T
*/
private fun simplifyLowerConstraint(typeVariable: KotlinTypeMarker, subType: KotlinTypeMarker): Boolean {
private fun simplifyLowerConstraint(
typeVariable: KotlinTypeMarker,
subType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean = false
): Boolean {
val lowerConstraint = when (typeVariable) {
is SimpleTypeMarker ->
/*
@@ -229,7 +245,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
else -> error("sealed")
}
addLowerConstraint(typeVariable.typeConstructor(), lowerConstraint)
addLowerConstraint(typeVariable.typeConstructor(), lowerConstraint, isFromNullabilityConstraint)
return true
}
@@ -31,7 +31,8 @@ class ConstraintIncorporator(
fun addNewIncorporatedConstraint(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
shouldTryUseDifferentFlexibilityForUpperType: Boolean
shouldTryUseDifferentFlexibilityForUpperType: Boolean,
isFromNullabilityConstraint: Boolean = false
)
fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext)
@@ -62,7 +63,7 @@ class ConstraintIncorporator(
if (constraint.kind != ConstraintKind.LOWER) {
getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.UPPER) {
addNewIncorporatedConstraint(it.type, constraint.type, shouldBeTypeVariableFlexible)
addNewIncorporatedConstraint(it.type, constraint.type, shouldBeTypeVariableFlexible, it.isNullabilityConstraint)
}
}
}
@@ -231,7 +232,10 @@ class ConstraintIncorporator(
val inputTypePosition = baseConstraint.position.from.safeAs<OnlyInputTypeConstraintPosition>()
val isNullabilityConstraint = isUsefulForNullabilityConstraint && newConstraint.isNullableNothing()
val isNewConstraintUsefulForNullability = isUsefulForNullabilityConstraint && newConstraint.isNullableNothing()
val isOtherConstraintUsefulForNullability = otherConstraint.isNullabilityConstraint && otherConstraint.type.isNullableNothing()
val isNullabilityConstraint = isNewConstraintUsefulForNullability || isOtherConstraintUsefulForNullability
val constraintContext = ConstraintContext(kind, derivedFrom, inputTypePosition, isNullabilityConstraint)
addNewIncorporatedConstraint(targetVariable, newConstraint, constraintContext)
@@ -181,13 +181,15 @@ class ConstraintInjector(
fun runIsSubtypeOf(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
shouldTryUseDifferentFlexibilityForUpperType: Boolean = false
shouldTryUseDifferentFlexibilityForUpperType: Boolean = false,
isFromNullabilityConstraint: Boolean = false
) {
fun isSubtypeOf(upperType: KotlinTypeMarker) =
AbstractTypeChecker.isSubtypeOf(
this@TypeCheckerContext as AbstractTypeCheckerContext,
lowerType,
upperType
upperType,
isFromNullabilityConstraint
)
if (!isSubtypeOf(upperType)) {
@@ -215,8 +217,11 @@ class ConstraintInjector(
override fun addUpperConstraint(typeVariable: TypeConstructorMarker, superType: KotlinTypeMarker) =
addConstraint(typeVariable, superType, UPPER)
override fun addLowerConstraint(typeVariable: TypeConstructorMarker, subType: KotlinTypeMarker) =
addConstraint(typeVariable, subType, LOWER)
override fun addLowerConstraint(
typeVariable: TypeConstructorMarker,
subType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean
) = addConstraint(typeVariable, subType, LOWER, isFromNullabilityConstraint)
private fun isCapturedTypeFromSubtyping(type: KotlinTypeMarker) =
when ((type as? CapturedTypeMarker)?.captureStatus()) {
@@ -226,22 +231,32 @@ class ConstraintInjector(
error("Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint())
}
private fun addConstraint(typeVariableConstructor: TypeConstructorMarker, type: KotlinTypeMarker, kind: ConstraintKind) {
private fun addConstraint(
typeVariableConstructor: TypeConstructorMarker,
type: KotlinTypeMarker,
kind: ConstraintKind,
isFromNullabilityConstraint: Boolean = false
) {
val typeVariable = c.allTypeVariables[typeVariableConstructor]
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
addNewIncorporatedConstraint(typeVariable, type, ConstraintContext(kind, emptySet(), isNullabilityConstraint = false))
addNewIncorporatedConstraint(
typeVariable,
type,
ConstraintContext(kind, emptySet(), isNullabilityConstraint = isFromNullabilityConstraint)
)
}
// from ConstraintIncorporator.Context
override fun addNewIncorporatedConstraint(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
shouldTryUseDifferentFlexibilityForUpperType: Boolean
shouldTryUseDifferentFlexibilityForUpperType: Boolean,
isFromNullabilityConstraint: Boolean
) {
if (lowerType === upperType) return
if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
runIsSubtypeOf(lowerType, upperType, shouldTryUseDifferentFlexibilityForUpperType)
runIsSubtypeOf(lowerType, upperType, shouldTryUseDifferentFlexibilityForUpperType, isFromNullabilityConstraint)
}
}