Propagate nullness flexibility into the result type from type variables in other constraints during result type finding, to prevent variable fixation to less flexible type

^KT-44540 Fixed
This commit is contained in:
Victor Petukhov
2021-01-26 19:10:48 +03:00
parent ce1f9882df
commit 977ac7cbe7
6 changed files with 129 additions and 1 deletions
@@ -40,7 +40,9 @@ class ResultTypeResolver(
findResultIfThereIsEqualsConstraint(c, variableWithConstraints)?.let { return it }
val subType = c.findSubType(variableWithConstraints)
val superType = c.findSuperType(variableWithConstraints)
// Super type should be the most flexible, sub type should be the least one
val superType = c.findSuperType(variableWithConstraints).makeFlexibleIfNecessary(c, variableWithConstraints.constraints)
return if (direction == ResolveDirection.TO_SUBTYPE || direction == ResolveDirection.UNKNOWN) {
c.resultType(subType, superType, variableWithConstraints)
} else {
@@ -48,6 +50,30 @@ class ResultTypeResolver(
}
}
/*
* We propagate nullness flexibility into the result type from type variables in other constraints
* to prevent variable fixation into less flexible type.
* Constraints:
* UPPER(TypeVariable(T)..TypeVariable(T)?)
* UPPER(Foo?)
* Result type = makeFlexibleIfNecessary(Foo?) = Foo!
*
* We don't propagate nullness flexibility in depth as it's non-determined for now (see KT-35534):
* CST(Bar<Foo>, Bar<Foo!>) = Bar<Foo!>
* CST(Bar<Foo!>, Bar<Foo>) = Bar<Foo>
* But: CST(Foo, Foo!) = CST(Foo!, Foo) = Foo!
*/
private fun KotlinTypeMarker?.makeFlexibleIfNecessary(c: Context, constraints: List<Constraint>) = with(c) {
when (val type = this@makeFlexibleIfNecessary) {
is SimpleTypeMarker -> {
if (constraints.any { it.type.typeConstructor().isTypeVariable() && it.type.hasFlexibleNullability() }) {
createFlexibleType(type.makeSimpleTypeDefinitelyNotNullOrNotNull(), type.withNullability(true))
} else type
}
else -> type
}
}
private fun Context.resultType(
firstCandidate: KotlinTypeMarker?,
secondCandidate: KotlinTypeMarker?,