diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt index 8d5e180b83f..8eab74bb77a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.* import org.jetbrains.kotlin.types.typeUtil.builtIns +import org.jetbrains.kotlin.types.typeUtil.contains abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) { @@ -28,6 +29,11 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT abstract fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) + override fun allowSubtypeViaLowerTypeForCapturedType(subType: SimpleType, superType: NewCapturedType) = + !subType.contains { it.anyBound(this::isMyTypeVariable) } + + override val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.TAKE_FIRST_FOR_SUBTYPING + override final fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? { assertInputTypes(subType, superType) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index 5037de9c01a..26ae5c430a1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.CapturedType import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SeveralSupertypesWithSameConstructorPolicy.* import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SupertypesPolicy import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.makeNullable @@ -156,7 +157,13 @@ object NewKotlinTypeChecker : KotlinTypeChecker { return StrictEqualityTypeChecker.strictEqualTypes(subType.makeNullableAsSpecified(false), superType.makeNullableAsSpecified(false)) } - if (superType is NewCapturedType && superType.lowerType != null && isSubtypeOf(subType, superType.lowerType)) return true + if (superType is NewCapturedType && + superType.lowerType != null && + allowSubtypeViaLowerTypeForCapturedType(subType, superType) && + isSubtypeOf(subType, superType.lowerType)) + { + return true + } (superType.constructor as? IntersectionTypeConstructor)?.let { assert(!superType.isMarkedNullable) { "Intersection type should not be marked nullable!: $superType" } @@ -193,7 +200,16 @@ object NewKotlinTypeChecker : KotlinTypeChecker { 1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().arguments, superType) else -> { // at least 2 supertypes with same constructors. Such case is rare - if (supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.arguments, superType) }) return true + when (sameConstructorPolicy) { + FORCE_NOT_SUBTYPE -> return false + TAKE_FIRST_FOR_SUBTYPING -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().arguments, superType) + + CHECK_ANY_OF_THEM, + INTERSECT_ARGUMENTS_AND_CHECK_AGAIN -> + if (supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.arguments, superType) }) return true + } + + if (sameConstructorPolicy != INTERSECT_ARGUMENTS_AND_CHECK_AGAIN) return false val newArguments = superConstructor.parameters.mapIndexed { index, _ -> val allProjections = supertypesWithSameConstructor.map { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt index 3e88a04ea3e..ba0a6683bc3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt @@ -33,6 +33,9 @@ open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowe return a == b } + open fun allowSubtypeViaLowerTypeForCapturedType(subType: SimpleType, superType: NewCapturedType): Boolean = true + open val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.INTERSECT_ARGUMENTS_AND_CHECK_AGAIN + internal inline fun runWithArgumentsSettings(subArgument: UnwrappedType, f: TypeCheckerContext.() -> T): T { if (argumentsDepth > 100) { error("Arguments depth is too high. Some related argument: $subArgument") @@ -117,5 +120,12 @@ open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowe } } + enum class SeveralSupertypesWithSameConstructorPolicy { + TAKE_FIRST_FOR_SUBTYPING, + FORCE_NOT_SUBTYPE, + CHECK_ANY_OF_THEM, + INTERSECT_ARGUMENTS_AND_CHECK_AGAIN + } + val UnwrappedType.isAllowedTypeVariable: Boolean get() = allowedTypeVariable && constructor is NewTypeVariableConstructor } \ No newline at end of file