Introduce type parameter's upper bound aware type approximator for intersection types

This commit is contained in:
Victor Petukhov
2021-06-16 18:53:39 +03:00
committed by TeamCityServer
parent 750f327878
commit 6a78e0a10c
2 changed files with 27 additions and 7 deletions
@@ -224,7 +224,8 @@ abstract class AbstractTypeApproximator(
TypeApproximatorConfiguration.IntersectionStrategy.ALLOWED -> if (!thereIsApproximation) return null else intersectTypes(newTypes)
TypeApproximatorConfiguration.IntersectionStrategy.TO_FIRST -> if (toSuper) newTypes.first() else return type.defaultResult(toSuper = false)
// commonSupertypeCalculator should handle flexible types correctly
TypeApproximatorConfiguration.IntersectionStrategy.TO_COMMON_SUPERTYPE -> {
TypeApproximatorConfiguration.IntersectionStrategy.TO_COMMON_SUPERTYPE,
TypeApproximatorConfiguration.IntersectionStrategy.TO_UPPER_BOUND_IF_SUPERTYPE -> {
if (!toSuper) return type.defaultResult(toSuper = false)
val resultType = commonSuperType(newTypes)
approximateToSuperType(resultType, conf) ?: resultType
@@ -449,13 +450,26 @@ abstract class AbstractTypeApproximator(
* In<Foo> <: In<subType(Foo)>
* Inv<in Foo> <: Inv<in subType(Foo)>
*/
val approximatedArgument = argumentType.let {
if (isApproximateDirectionToSuper(effectiveVariance, toSuper)) {
approximateToSuperType(it, conf, depth)
val approximatedArgument = if (isApproximateDirectionToSuper(effectiveVariance, toSuper)) {
val approximatedType = approximateToSuperType(argumentType, conf, depth)
if (conf.intersection == TypeApproximatorConfiguration.IntersectionStrategy.TO_UPPER_BOUND_IF_SUPERTYPE
&& argumentType.typeConstructor().isIntersection()
&& parameter.getUpperBounds().all { AbstractTypeChecker.isSubtypeOf(ctx, argumentType, it) }
) {
val intersectedUpperBounds = intersectTypes(parameter.getUpperBounds())
if (approximatedType == null
|| !AbstractTypeChecker.isSubtypeOf(ctx, approximatedType, intersectedUpperBounds)
) {
intersectedUpperBounds
} else {
approximatedType
}
} else {
approximateToSubType(it, conf, depth)
approximatedType ?: continue@loop
}
} ?: continue@loop
} else {
approximateToSubType(argumentType, conf, depth) ?: continue@loop
}
if (
conf.intersection != TypeApproximatorConfiguration.IntersectionStrategy.ALLOWED &&
@@ -11,7 +11,8 @@ open class TypeApproximatorConfiguration {
enum class IntersectionStrategy {
ALLOWED,
TO_FIRST,
TO_COMMON_SUPERTYPE
TO_COMMON_SUPERTYPE,
TO_UPPER_BOUND_IF_SUPERTYPE
}
open val flexible: Boolean get() = false // simple flexible types (FlexibleTypeImpl)
@@ -87,4 +88,9 @@ open class TypeApproximatorConfiguration {
override fun capturedType(ctx: TypeSystemInferenceExtensionContext, type: CapturedTypeMarker): Boolean = true
}
object UpperBoundAwareIntersectionTypeApproximator : AllFlexibleSameValue() {
override val allFlexible: Boolean get() = true
override val intersection: IntersectionStrategy = IntersectionStrategy.TO_UPPER_BOUND_IF_SUPERTYPE
}
}