EmptyIntersectionTypeChecker: drop also incompatible supertypes check

Incompatible supertypes check also don't provoke runtime problems
in most situations, because this check is also bound to type argument
conflict. Related to KT-54411
This commit is contained in:
Mikhail Glukhikh
2022-12-05 11:31:20 +01:00
committed by Space Team
parent 29ad5f981c
commit 758a4931e3
6 changed files with 4 additions and 91 deletions
@@ -1,16 +0,0 @@
class Foo<T>
class Bar<T> {
fun <S : T> takeFoo(foo: Foo<in S>) {}
}
class Out<out P>
interface A<K>
interface B<T> : A<T>
interface C<T> : A<T>
fun <K : C<Int>> main() {
val foo = Foo<K>()
Bar<B<String>>().<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION!>takeFoo<!>(foo) // error in 1.3.72, no error in 1.4.31
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
class Foo<T>
class Bar<T> {
@@ -12,5 +13,5 @@ interface C<T> : A<T>
fun <K : C<Int>> main() {
val foo = Foo<K>()
Bar<B<String>>().<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>takeFoo<!>(foo) // error in 1.3.72, no error in 1.4.31
Bar<B<String>>().takeFoo(foo) // error in 1.3.72, no error in 1.4.31
}
@@ -1,18 +0,0 @@
class Foo<T>
class Bar<T> {
fun <S : T> takeFoo(foo: Foo<in S>) {}
}
class Out<out P>
interface A<K>
interface B2<T> : A<T>
interface C2<T> : A<T>
interface B<T> : B2<T>
interface C<T> : C2<T>
fun <K : C<Int>> main() {
val foo = Foo<K>()
Bar<B<String>>().<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION!>takeFoo<!>(foo) // error in 1.3.72, no error in 1.4.31
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
class Foo<T>
class Bar<T> {
@@ -14,5 +15,5 @@ interface C<T> : C2<T>
fun <K : C<Int>> main() {
val foo = Foo<K>()
Bar<B<String>>().<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>takeFoo<!>(foo) // error in 1.3.72, no error in 1.4.31
Bar<B<String>>().takeFoo(foo) // error in 1.3.72, no error in 1.4.31
}
@@ -101,10 +101,6 @@ internal object EmptyIntersectionTypeChecker {
return EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.MULTIPLE_CLASSES, firstType, secondType)
}
firstTypeConstructor.isFinalClassConstructor() || secondTypeConstructor.isFinalClassConstructor() -> {
val incompatibleSupertypes = getIncompatibleSuperTypes(firstType, secondType)
if (incompatibleSupertypes != null) {
return EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.INCOMPATIBLE_SUPERTYPES, *incompatibleSupertypes)
}
// don't have incompatible supertypes so can have a common subtype only if all types are interfaces
possibleEmptyIntersectionKind = EmptyIntersectionTypeInfo(
EmptyIntersectionTypeKind.FINAL_CLASS_AND_INTERFACE,
@@ -125,56 +121,6 @@ internal object EmptyIntersectionTypeChecker {
typeCheckerState, this, otherConstructorMarker
).isNotEmpty()
private fun TypeSystemInferenceExtensionContext.getIncompatibleSuperTypes(
firstType: KotlinTypeMarker, secondType: KotlinTypeMarker
): Array<KotlinTypeMarker>? {
@Suppress("NAME_SHADOWING")
val firstType = firstType.eraseContainingTypeParameters()
@Suppress("NAME_SHADOWING")
val secondType = secondType.eraseContainingTypeParameters()
// interface A<K>
// interface B: A<String>
// interface C: A<Int>
// => B and C have incompatible supertypes
val superTypesOfFirst = firstType.typeConstructor().supertypes()
val firstTypeSubstitutor = createSubstitutorForSuperTypes(firstType)
val superTypesOfSecond = secondType.typeConstructor().supertypes()
val secondTypeSubstitutor = createSubstitutorForSuperTypes(secondType)
for (superTypeOfFirst in superTypesOfFirst) {
@Suppress("NAME_SHADOWING")
val superTypeOfFirst = firstTypeSubstitutor?.safeSubstitute(superTypeOfFirst) ?: superTypeOfFirst
if (areIncompatibleSuperTypes(superTypeOfFirst, secondType))
return arrayOf(superTypeOfFirst, secondType)
for (superTypeOfSecond in superTypesOfSecond) {
@Suppress("NAME_SHADOWING")
val superTypeOfSecond = secondTypeSubstitutor?.safeSubstitute(superTypeOfSecond) ?: superTypeOfSecond
if (areIncompatibleSuperTypes(firstType, superTypeOfSecond))
return arrayOf(firstType, superTypeOfSecond)
if (areIncompatibleSuperTypes(superTypeOfFirst, superTypeOfSecond))
return arrayOf(superTypeOfFirst, superTypeOfSecond)
getIncompatibleSuperTypes(superTypeOfFirst, superTypeOfSecond)?.let { return it }
}
}
return null
}
private fun TypeSystemInferenceExtensionContext.areIncompatibleSuperTypes(
firstType: KotlinTypeMarker, secondType: KotlinTypeMarker
): Boolean = firstType.typeConstructor() == secondType.typeConstructor()
&& !AbstractTypeChecker.equalTypes(
newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = true),
firstType, secondType
)
private fun TypeSystemInferenceExtensionContext.mayCauseEmptyIntersection(type: KotlinTypeMarker): Boolean {
val typeConstructor = type.typeConstructor()
@@ -7,6 +7,5 @@ package org.jetbrains.kotlin.types
enum class EmptyIntersectionTypeKind(val description: String, val isDefinitelyEmpty: Boolean) {
MULTIPLE_CLASSES("multiple incompatible classes", isDefinitelyEmpty = true),
INCOMPATIBLE_SUPERTYPES("incompatible supertypes", isDefinitelyEmpty = true),
FINAL_CLASS_AND_INTERFACE("final class and interface", isDefinitelyEmpty = false)
}