[NI] Do not run "or" branches for constraint subtyping.
We should never do that, because otherwise we can get unexpected result. Example for input constraint: C(in String) <: T. If we run usual subtyping algorithm, then we get 2 constraints: C(in String) <: T and T <: String. Of course such system has contradiction.
This commit is contained in:
+6
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
|||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.checker.*
|
import org.jetbrains.kotlin.types.checker.*
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
|
|
||||||
abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) {
|
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 addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType)
|
||||||
abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: 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? {
|
override final fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||||
assertInputTypes(subType, superType)
|
assertInputTypes(subType, superType)
|
||||||
|
|
||||||
|
|||||||
@@ -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.calls.inference.CapturedTypeConstructor
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.*
|
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.checker.TypeCheckerContext.SupertypesPolicy
|
||||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
@@ -156,7 +157,13 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
|||||||
return StrictEqualityTypeChecker.strictEqualTypes(subType.makeNullableAsSpecified(false), superType.makeNullableAsSpecified(false))
|
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 {
|
(superType.constructor as? IntersectionTypeConstructor)?.let {
|
||||||
assert(!superType.isMarkedNullable) { "Intersection type should not be marked nullable!: $superType" }
|
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)
|
1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().arguments, superType)
|
||||||
|
|
||||||
else -> { // at least 2 supertypes with same constructors. Such case is rare
|
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 newArguments = superConstructor.parameters.mapIndexed { index, _ ->
|
||||||
val allProjections = supertypesWithSameConstructor.map {
|
val allProjections = supertypesWithSameConstructor.map {
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowe
|
|||||||
return a == b
|
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 <T> runWithArgumentsSettings(subArgument: UnwrappedType, f: TypeCheckerContext.() -> T): T {
|
internal inline fun <T> runWithArgumentsSettings(subArgument: UnwrappedType, f: TypeCheckerContext.() -> T): T {
|
||||||
if (argumentsDepth > 100) {
|
if (argumentsDepth > 100) {
|
||||||
error("Arguments depth is too high. Some related argument: $subArgument")
|
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
|
val UnwrappedType.isAllowedTypeVariable: Boolean get() = allowedTypeVariable && constructor is NewTypeVariableConstructor
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user