[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:
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+28
-7
@@ -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() {
|
||||
}
|
||||
Generated
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user