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:
committed by
Space Team
parent
29ad5f981c
commit
758a4931e3
Vendored
-16
@@ -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
|
|
||||||
}
|
|
||||||
Vendored
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
class Foo<T>
|
class Foo<T>
|
||||||
|
|
||||||
class Bar<T> {
|
class Bar<T> {
|
||||||
@@ -12,5 +13,5 @@ interface C<T> : A<T>
|
|||||||
|
|
||||||
fun <K : C<Int>> main() {
|
fun <K : C<Int>> main() {
|
||||||
val foo = Foo<K>()
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-18
@@ -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
|
|
||||||
}
|
|
||||||
Vendored
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
class Foo<T>
|
class Foo<T>
|
||||||
|
|
||||||
class Bar<T> {
|
class Bar<T> {
|
||||||
@@ -14,5 +15,5 @@ interface C<T> : C2<T>
|
|||||||
|
|
||||||
fun <K : C<Int>> main() {
|
fun <K : C<Int>> main() {
|
||||||
val foo = Foo<K>()
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
-54
@@ -101,10 +101,6 @@ internal object EmptyIntersectionTypeChecker {
|
|||||||
return EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.MULTIPLE_CLASSES, firstType, secondType)
|
return EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.MULTIPLE_CLASSES, firstType, secondType)
|
||||||
}
|
}
|
||||||
firstTypeConstructor.isFinalClassConstructor() || secondTypeConstructor.isFinalClassConstructor() -> {
|
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
|
// don't have incompatible supertypes so can have a common subtype only if all types are interfaces
|
||||||
possibleEmptyIntersectionKind = EmptyIntersectionTypeInfo(
|
possibleEmptyIntersectionKind = EmptyIntersectionTypeInfo(
|
||||||
EmptyIntersectionTypeKind.FINAL_CLASS_AND_INTERFACE,
|
EmptyIntersectionTypeKind.FINAL_CLASS_AND_INTERFACE,
|
||||||
@@ -125,56 +121,6 @@ internal object EmptyIntersectionTypeChecker {
|
|||||||
typeCheckerState, this, otherConstructorMarker
|
typeCheckerState, this, otherConstructorMarker
|
||||||
).isNotEmpty()
|
).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 {
|
private fun TypeSystemInferenceExtensionContext.mayCauseEmptyIntersection(type: KotlinTypeMarker): Boolean {
|
||||||
val typeConstructor = type.typeConstructor()
|
val typeConstructor = type.typeConstructor()
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,5 @@ package org.jetbrains.kotlin.types
|
|||||||
|
|
||||||
enum class EmptyIntersectionTypeKind(val description: String, val isDefinitelyEmpty: Boolean) {
|
enum class EmptyIntersectionTypeKind(val description: String, val isDefinitelyEmpty: Boolean) {
|
||||||
MULTIPLE_CLASSES("multiple incompatible classes", isDefinitelyEmpty = true),
|
MULTIPLE_CLASSES("multiple incompatible classes", isDefinitelyEmpty = true),
|
||||||
INCOMPATIBLE_SUPERTYPES("incompatible supertypes", isDefinitelyEmpty = true),
|
|
||||||
FINAL_CLASS_AND_INTERFACE("final class and interface", isDefinitelyEmpty = false)
|
FINAL_CLASS_AND_INTERFACE("final class and interface", isDefinitelyEmpty = false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user