[FE] Fix TypeParameterUpperBounds incompatibility priority

^KT-60902 Fixed
Review: https://jetbrains.team/p/kt/reviews/11039/timeline

We should prioritize to return STRONG incompatibilities over WEAK
incompatibilities. But this invariant broke in `areCompatibleCallables`,
because `areCompatibleTypeParameters` returns incompatibilities of both
types, and `areCompatibleTypeParameters` is called in WEAK
incompatibilities section.

The fix is to split `areCompatibleTypeParameters` into two functions:
`areStrongIncompatibleTypeParameters` and
`areWeakIncompatibleTypeParameters`. And call each of this function in
appropriate `areCompatibleCallables` sections.
This commit is contained in:
Nikita Bobko
2023-08-02 19:12:41 +02:00
committed by teamcity
parent fd5e97ff23
commit eac4b81b11
5 changed files with 59 additions and 7 deletions
@@ -205,6 +205,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/kt58153.kt");
}
@Test
@TestMetadata("kt60902.kt")
public void testKt60902() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/kt60902.kt");
}
@Test
@TestMetadata("manyImplMemberNotImplemented.kt")
public void testManyImplMemberNotImplemented() throws Exception {
@@ -205,6 +205,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/kt58153.kt");
}
@Test
@TestMetadata("kt60902.kt")
public void testKt60902() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/kt60902.kt");
}
@Test
@TestMetadata("manyImplMemberNotImplemented.kt")
public void testManyImplMemberNotImplemented() throws Exception {
@@ -298,6 +298,8 @@ object AbstractExpectActualCompatibilityChecker {
return ExpectActualCompatibility.Compatible
}
// ALL THE FOLLOWING ARE STRONG INCOMPATIBILITIES
if (expectDeclaration is FunctionSymbolMarker != actualDeclaration is FunctionSymbolMarker) {
return Incompatible.CallableKind
}
@@ -345,6 +347,10 @@ object AbstractExpectActualCompatibilityChecker {
}
}
areStrongIncompatibleTypeParameters(expectedTypeParameters, actualTypeParameters, substitutor)?.let { return it }
// ALL THE FOLLOWING ARE WEAK INCOMPATIBILITIES
if (actualDeclaration.hasStableParameterNames && !equalsBy(expectedValueParameters, actualValueParameters) { it.name }) {
return Incompatible.ParameterNames
}
@@ -370,11 +376,7 @@ object AbstractExpectActualCompatibilityChecker {
return Incompatible.Visibility
}
areCompatibleTypeParameters(expectedTypeParameters, actualTypeParameters, substitutor).let {
if (it != ExpectActualCompatibility.Compatible) {
return it
}
}
areWeakIncompatibleTypeParameters(expectedTypeParameters, actualTypeParameters)?.let { return it }
if (shouldCheckAbsenceOfDefaultParamsInActual) {
// "Default parameters in actual" check is required only for functions, because only functions can have parameters
@@ -535,7 +537,18 @@ object AbstractExpectActualCompatibilityChecker {
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
actualTypeParameterSymbols: List<TypeParameterSymbolMarker>,
substitutor: TypeSubstitutorMarker,
): ExpectActualCompatibility<*> {
): ExpectActualCompatibility<*> =
// We must prioritize to return STRONG incompatible over WEAK incompatible (because STRONG incompatibility allows to search for overloads)
areStrongIncompatibleTypeParameters(expectTypeParameterSymbols, actualTypeParameterSymbols, substitutor)
?: areWeakIncompatibleTypeParameters(expectTypeParameterSymbols, actualTypeParameterSymbols)
?: ExpectActualCompatibility.Compatible
context(ExpectActualMatchingContext<*>)
private fun areStrongIncompatibleTypeParameters(
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
actualTypeParameterSymbols: List<TypeParameterSymbolMarker>,
substitutor: TypeSubstitutorMarker,
): Incompatible<*>? {
for (i in expectTypeParameterSymbols.indices) {
val expectBounds = expectTypeParameterSymbols[i].bounds
val actualBounds = actualTypeParameterSymbols[i].bounds
@@ -547,6 +560,14 @@ object AbstractExpectActualCompatibilityChecker {
}
}
return null
}
context(ExpectActualMatchingContext<*>)
private fun areWeakIncompatibleTypeParameters(
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
actualTypeParameterSymbols: List<TypeParameterSymbolMarker>,
): Incompatible<*>? {
if (!equalsBy(expectTypeParameterSymbols, actualTypeParameterSymbols) { it.variance }) {
return Incompatible.TypeParameterVariance
}
@@ -560,7 +581,7 @@ object AbstractExpectActualCompatibilityChecker {
return Incompatible.TypeParameterReified
}
return ExpectActualCompatibility.Compatible
return null
}
context(ExpectActualMatchingContext<*>)
@@ -0,0 +1,13 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
public expect fun <T : Comparable<T>> Array<out T>.foo()
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
public actual fun <T : Comparable<T>> Array<out T>.foo() {
}
private fun <T> Array<out T>.foo() {
}
@@ -22884,6 +22884,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/kt58153.kt");
}
@Test
@TestMetadata("kt60902.kt")
public void testKt60902() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/kt60902.kt");
}
@Test
@TestMetadata("manyImplMemberNotImplemented.kt")
public void testManyImplMemberNotImplemented() throws Exception {