From 6a78e0a10c90a6679e517c45edaa2f7acab28b3b Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Wed, 16 Jun 2021 18:53:39 +0300 Subject: [PATCH] Introduce type parameter's upper bound aware type approximator for intersection types --- .../kotlin/types/AbstractTypeApproximator.kt | 26 ++++++++++++++----- .../types/TypeApproximatorConfiguration.kt | 8 +++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt index 8ae70e9277d..156fe9beb1d 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt @@ -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 <: In * Inv <: Inv */ - 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 && diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/types/TypeApproximatorConfiguration.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/types/TypeApproximatorConfiguration.kt index ba749411d4d..914637e8238 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/types/TypeApproximatorConfiguration.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/types/TypeApproximatorConfiguration.kt @@ -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 + } }