EmptyIntersectionTypeChecker: drop questionable check of arguments

The situations with conflicting type arguments normally don't provoke
any runtime problems. Also, conflicts like A<T> VS A<SomeType> aren't
valid at all. Here we decided to remove them to avoid strange
and non-actionable warnings in user code.

#KT-54411 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-11-24 18:07:40 +01:00
committed by Space Team
parent 832baf81e5
commit 2a1a5c6936
51 changed files with 42 additions and 420 deletions
@@ -107,18 +107,10 @@ internal object EmptyIntersectionTypeChecker {
).singleOrNull()
when {
firstSuperTypeWithSecondConstructor != null && secondSuperTypeByFirstConstructor != null -> {
val argumentsIntersectionKind = computeByCheckingTypeArguments(
firstSuperTypeWithSecondConstructor, secondSuperTypeByFirstConstructor
) ?: continue
if (argumentsIntersectionKind.kind.isDefinitelyEmpty())
return argumentsIntersectionKind
if (possibleEmptyIntersectionKind == null && argumentsIntersectionKind.kind.isPossiblyEmpty())
possibleEmptyIntersectionKind = argumentsIntersectionKind
firstSuperTypeWithSecondConstructor != null || secondSuperTypeByFirstConstructor != null -> {
continue
}
firstSuperTypeWithSecondConstructor == null && secondSuperTypeByFirstConstructor == null && !atLeastOneInterface -> {
!atLeastOneInterface -> {
// Two classes can't have a common subtype if neither is a subtype of another
return EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.MULTIPLE_CLASSES, firstType, secondType)
}
@@ -140,70 +132,6 @@ internal object EmptyIntersectionTypeChecker {
return possibleEmptyIntersectionKind
}
private fun TypeSystemInferenceExtensionContext.computeByCheckingTypeArguments(
firstType: KotlinTypeMarker,
secondType: KotlinTypeMarker,
): EmptyIntersectionTypeInfo? {
require(firstType.typeConstructor() == secondType.typeConstructor()) {
"Type constructors of the passed types should be the same to compare their arguments"
}
fun isSubtypeOf(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker) =
AbstractTypeChecker.isSubtypeOf(this, firstType, secondType)
fun areEqualTypes(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker) =
AbstractTypeChecker.equalTypes(this, firstType, secondType)
fun Boolean.toEmptyIntersectionKind(vararg types: KotlinTypeMarker) =
if (this) null else EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.INCOMPATIBLE_TYPE_ARGUMENTS, *types)
var possibleEmptyIntersectionTypeInfo: EmptyIntersectionTypeInfo? = null
for ((i, argumentOfFirst) in firstType.getArguments().withIndex()) {
@Suppress("NAME_SHADOWING")
val argumentOfFirst = uncaptureIfNeeded(argumentOfFirst)
val argumentOfSecond = uncaptureIfNeeded(secondType.getArgument(i))
if (argumentOfFirst == argumentOfSecond || argumentOfFirst.isStarProjection() || argumentOfSecond.isStarProjection())
continue
val argumentTypeOfFirst = argumentOfFirst.getType()
val argumentTypeOfSecond = argumentOfSecond.getType()
val intersectionKindOfArguments = when {
areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.INV, TypeVariance.INV) ->
areEqualTypes(argumentTypeOfFirst, argumentTypeOfSecond)
.toEmptyIntersectionKind(argumentTypeOfFirst, argumentTypeOfSecond)
areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.INV, TypeVariance.OUT) ->
isSubtypeOf(argumentTypeOfFirst, argumentTypeOfSecond)
.toEmptyIntersectionKind(argumentTypeOfFirst, argumentTypeOfSecond)
areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.INV, TypeVariance.IN) ->
isSubtypeOf(argumentTypeOfSecond, argumentTypeOfFirst)
.toEmptyIntersectionKind(argumentTypeOfFirst, argumentTypeOfSecond)
areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.IN, TypeVariance.OUT) -> {
if (argumentTypeOfFirst.argumentsCount() == 0 && argumentTypeOfSecond.argumentsCount() == 0) {
isSubtypeOf(argumentTypeOfFirst, argumentTypeOfSecond)
.toEmptyIntersectionKind(argumentTypeOfFirst, argumentTypeOfSecond)
} else {
computeByHavingCommonSubtype(argumentTypeOfFirst, argumentTypeOfSecond)
}
}
areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.OUT, TypeVariance.OUT)
|| areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.IN, TypeVariance.IN) -> {
computeByHavingCommonSubtype(argumentTypeOfFirst, argumentTypeOfSecond)
}
else -> true.toEmptyIntersectionKind(argumentTypeOfFirst, argumentTypeOfSecond)
} ?: continue
if (intersectionKindOfArguments.kind.isDefinitelyEmpty())
return intersectionKindOfArguments
if (possibleEmptyIntersectionTypeInfo == null && intersectionKindOfArguments.kind.isPossiblyEmpty())
possibleEmptyIntersectionTypeInfo = intersectionKindOfArguments
}
return possibleEmptyIntersectionTypeInfo
}
private fun TypeSystemInferenceExtensionContext.getIncompatibleSuperTypes(
firstType: KotlinTypeMarker, secondType: KotlinTypeMarker
): Array<KotlinTypeMarker>? {
@@ -268,30 +196,6 @@ internal object EmptyIntersectionTypeChecker {
return !typeConstructor.isAnyConstructor() && !typeConstructor.isNothingConstructor()
}
private fun TypeSystemInferenceExtensionContext.areArgumentsOfSpecifiedVariances(
firstType: KotlinTypeMarker,
secondType: KotlinTypeMarker,
argumentIndex: Int,
variance1: TypeVariance,
variance2: TypeVariance,
): Boolean {
fun getEffectiveVariance(type: KotlinTypeMarker): TypeVariance? {
val argument = uncaptureIfNeeded(type.getArgument(argumentIndex))
val parameter = type.typeConstructor().getParameter(argumentIndex)
return AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
}
val effectiveVariance1 = getEffectiveVariance(firstType)
val effectiveVariance2 = getEffectiveVariance(secondType)
return (effectiveVariance1 == variance1 && effectiveVariance2 == variance2)
|| (effectiveVariance1 == variance2 && effectiveVariance2 == variance1)
}
private fun TypeSystemInferenceExtensionContext.uncaptureIfNeeded(argument: TypeArgumentMarker): TypeArgumentMarker {
val type = argument.getType()
return if (type is CapturedTypeMarker) type.typeConstructorProjection() else argument
}
}
class EmptyIntersectionTypeInfo(val kind: EmptyIntersectionTypeKind, vararg val casingTypes: KotlinTypeMarker)