NI: Fix some unwanted exclusions constraints with remained corresponding optimization

This commit is contained in:
victor.petukhov
2019-12-05 16:19:18 +03:00
parent 15f6beed57
commit 2d5a05466d
2 changed files with 49 additions and 5 deletions
@@ -157,6 +157,11 @@ class ConstraintIncorporator(
isSubtype: Boolean
) {
if (targetVariable in getNestedTypeVariables(newConstraint)) return
val isUsefulForNullabilityConstraint =
isPotentialUsefulNullabilityConstraint(newConstraint, otherConstraint.type, otherConstraint.kind)
if (!isUsefulForNullabilityConstraint && !containsConstrainingTypeWithoutProjection(newConstraint, otherConstraint)) return
if (trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(
baseConstraint, otherConstraint, newConstraint, isSubtype
)
@@ -172,6 +177,28 @@ class ConstraintIncorporator(
addNewIncorporatedConstraint(targetVariable, newConstraint, ConstraintContext(kind, derivedFrom))
}
fun Context.containsConstrainingTypeWithoutProjection(
newConstraint: KotlinTypeMarker,
otherConstraint: Constraint
): Boolean {
return getNestedArguments(newConstraint).any {
it.getType().typeConstructor() == otherConstraint.type.typeConstructor() && it.getVariance() == TypeVariance.INV
}
}
private fun Context.isPotentialUsefulNullabilityConstraint(
newConstraint: KotlinTypeMarker,
otherConstraint: KotlinTypeMarker,
kind: ConstraintKind
): Boolean {
val otherConstraintCanAddNullabilityToNewOne =
!newConstraint.isNullableType() && otherConstraint.isNullableType() && kind == ConstraintKind.LOWER
val newConstraintCanAddNullabilityToOtherOne =
newConstraint.isNullableType() && !otherConstraint.isNullableType() && kind == ConstraintKind.UPPER
return otherConstraintCanAddNullabilityToNewOne || newConstraintCanAddNullabilityToOtherOne
}
fun Context.getNestedTypeVariables(type: KotlinTypeMarker): List<TypeVariableMarker> =
getNestedArguments(type).mapNotNull { getTypeVariable(it.getType().typeConstructor()) }
@@ -189,19 +216,36 @@ class ConstraintIncorporator(
private fun TypeSystemInferenceExtensionContext.getNestedArguments(type: KotlinTypeMarker): List<TypeArgumentMarker> {
val result = ArrayList<TypeArgumentMarker>()
val stack = ArrayDeque<TypeArgumentMarker>()
when (type) {
is FlexibleType -> {
stack.push(createTypeArgument(type.lowerBound, TypeVariance.INV))
stack.push(createTypeArgument(type.upperBound, TypeVariance.INV))
}
else -> stack.push(createTypeArgument(type, TypeVariance.INV))
}
stack.push(createTypeArgument(type, TypeVariance.INV))
val addArgumentsToStack = { projectedType: KotlinTypeMarker ->
for (argumentIndex in 0 until projectedType.argumentsCount()) {
stack.add(projectedType.getArgument(argumentIndex))
}
}
while (!stack.isEmpty()) {
val typeProjection = stack.pop()
if (typeProjection.isStarProjection()) continue
result.add(typeProjection)
val projectedType = typeProjection.getType()
for (argumentIndex in 0 until projectedType.argumentsCount()) {
stack.add(projectedType.getArgument(argumentIndex))
when (val projectedType = typeProjection.getType()) {
is FlexibleType -> {
addArgumentsToStack(projectedType.lowerBound)
addArgumentsToStack(projectedType.upperBound)
}
else -> addArgumentsToStack(projectedType)
}
}
return result
@@ -2,4 +2,4 @@
fun <T : Any> nullable(): T? = null
val value = nullable<Int>() <!NI;TYPE_MISMATCH!>?:<!> <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>nullable()<!>
val value = nullable<Int>() ?: <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>nullable()<!>