diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt index 32f8b96f433..32f96ec2548 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -382,7 +382,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker { object Modality : Incompatible("modality is different") object Visibility : Incompatible("visibility is different") - object TypeParameterUpperBounds : Incompatible("upper bounds of type parameters are different") + object TypeParameterUpperBounds : Incompatible("upper bounds of type parameters are different", IncompatibilityKind.STRONG) object TypeParameterVariance : Incompatible("declaration-site variances of type parameters are different") object TypeParameterReified : Incompatible("some type parameter is reified in one declaration and non-reified in the other") @@ -523,8 +523,14 @@ object ExpectedActualDeclarationChecker : DeclarationChecker { platformModule: ModuleDescriptor, substitutor: Substitutor ): Compatibility { - if (!areCompatibleTypeLists(a.map { substitutor(it.defaultType) }, b.map { it.defaultType }, platformModule)) - return Incompatible.TypeParameterUpperBounds + for (i in a.indices) { + val aBounds = a[i].upperBounds + val bBounds = b[i].upperBounds + if (aBounds.size != bBounds.size || !areCompatibleTypeLists(aBounds.map(substitutor), bBounds, platformModule)) { + return Incompatible.TypeParameterUpperBounds + } + } + if (!equalsBy(a, b, TypeParameterDescriptor::getVariance)) return Incompatible.TypeParameterVariance // Removing "reified" from an expected function's type parameter is fine diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.kt b/compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.kt new file mode 100644 index 00000000000..8023137fd55 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.kt @@ -0,0 +1,12 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +expect fun > Array.sort(): Unit + +// MODULE: m2-jvm(m1-common) +// FILE: jvm.kt + +actual fun > Array.sort(): Unit {} + +fun Array.sort(): Unit {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.txt b/compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.txt new file mode 100644 index 00000000000..3188e209d3e --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.txt @@ -0,0 +1,11 @@ +// -- Module: -- +package + +public expect fun > kotlin.Array.sort(): kotlin.Unit + + +// -- Module: -- +package + +public fun kotlin.Array.sort(): kotlin.Unit +public actual fun > kotlin.Array.sort(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.kt b/compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.kt new file mode 100644 index 00000000000..e13adfe8d64 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.kt @@ -0,0 +1,25 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +expect class A { + fun foo(): Unit + + fun > bar(): List +} + +// MODULE: m2-jvm(m1-common) +// FILE: jvm.kt + +actual typealias A = JavaA + +// FILE: JavaA.java +import java.util.List; + +public class JavaA { + public void foo() {} + + public > List bar() { + return null; + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.txt b/compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.txt new file mode 100644 index 00000000000..fc175f38e22 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.txt @@ -0,0 +1,24 @@ +// -- Module: -- +package + +public final expect class A { + public final expect fun > bar(): kotlin.collections.List + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final expect fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + + +// -- Module: -- +package + +public open class JavaA { + public constructor JavaA() + public open fun !> bar(): kotlin.collections.(Mutable)List! + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} +public actual typealias A = JavaA diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.kt b/compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.kt new file mode 100644 index 00000000000..8b34494e63b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.kt @@ -0,0 +1,13 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +interface A +interface B + +expect fun List.foo() where T : A, T : B + +// MODULE: m2-jvm(m1-common) +// FILE: jvm.kt + +fun List.foo() where T : B, T : A {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.txt b/compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.txt new file mode 100644 index 00000000000..fe69e8e0bb0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.txt @@ -0,0 +1,34 @@ +// -- Module: -- +package + +public expect fun kotlin.collections.List.foo(): kotlin.Unit where T : B + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + + +// -- Module: -- +package + +public fun kotlin.collections.List.foo(): kotlin.Unit where T : A + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/multiplatform/incompatibleCallables/output.txt b/compiler/testData/multiplatform/incompatibleCallables/output.txt index a39b8696040..7379739d9e7 100644 --- a/compiler/testData/multiplatform/incompatibleCallables/output.txt +++ b/compiler/testData/multiplatform/incompatibleCallables/output.txt @@ -50,6 +50,24 @@ The following declaration is incompatible because number of type parameters is d expect fun f7() ^ +compiler/testData/multiplatform/incompatibleCallables/common.kt:19:12: error: expected function 'f11' has no actual declaration in module +The following declaration is incompatible because upper bounds of type parameters are different: + public actual fun f11(): Unit + +expect fun f11() + ^ +compiler/testData/multiplatform/incompatibleCallables/common.kt:20:12: error: expected function 'f12' has no actual declaration in module +The following declaration is incompatible because upper bounds of type parameters are different: + public actual fun > f12(): Unit + +expect fun > f12() + ^ +compiler/testData/multiplatform/incompatibleCallables/common.kt:21:12: error: expected function 'f13' has no actual declaration in module +The following declaration is incompatible because upper bounds of type parameters are different: + public actual fun > f13(): Unit + +expect fun > f13() + ^ compiler/testData/multiplatform/incompatibleCallables/common.kt:32:15: error: expected function 'f21' has no actual declaration in module The following declaration is incompatible because parameter types are different: public actual fun f21(c: Unit.() -> Unit): Unit @@ -122,6 +140,24 @@ The following declaration is incompatible because visibility is different: internal actual fun f10() {} ^ +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:19:12: error: actual function 'f11' has no corresponding expected declaration +The following declaration is incompatible because upper bounds of type parameters are different: + public expect fun f11(): Unit + +actual fun f11() {} + ^ +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:20:12: error: actual function 'f12' has no corresponding expected declaration +The following declaration is incompatible because upper bounds of type parameters are different: + public expect fun > f12(): Unit + +actual fun > f12() {} + ^ +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:21:12: error: actual function 'f13' has no corresponding expected declaration +The following declaration is incompatible because upper bounds of type parameters are different: + public expect fun > f13(): Unit + +actual fun > f13() {} + ^ compiler/testData/multiplatform/incompatibleCallables/jvm.kt:23:19: error: actual function 'f14' has no corresponding expected declaration The following declaration is incompatible because some type parameter is reified in one declaration and non-reified in the other: public expect inline fun f14(): Unit diff --git a/compiler/testData/multiplatform/incompatibleClasses/output.txt b/compiler/testData/multiplatform/incompatibleClasses/output.txt index 02a75b8a3a1..2a4bb7d59e7 100644 --- a/compiler/testData/multiplatform/incompatibleClasses/output.txt +++ b/compiler/testData/multiplatform/incompatibleClasses/output.txt @@ -11,6 +11,18 @@ The following declaration is incompatible because number of type parameters is d expect class C1 ^ +compiler/testData/multiplatform/incompatibleClasses/common.kt:16:16: error: expected class 'C3' has no actual declaration in module +The following declaration is incompatible because upper bounds of type parameters are different: + public final actual class C3 + +expect class C3 + ^ +compiler/testData/multiplatform/incompatibleClasses/common.kt:18:16: error: expected class 'C4' has no actual declaration in module +The following declaration is incompatible because upper bounds of type parameters are different: + public typealias C4 = C4Impl + +expect class C4 + ^ compiler/testData/multiplatform/incompatibleClasses/jvm.kt:1:8: error: actual interface 'PClass' has no corresponding expected declaration The following declaration is incompatible because class kinds are different (class, interface, object, enum, annotation): public final expect class PClass @@ -83,6 +95,18 @@ The following declaration is incompatible because declaration-site variances of actual class C2 ^ +compiler/testData/multiplatform/incompatibleClasses/jvm.kt:16:16: error: actual class 'C3' has no corresponding expected declaration +The following declaration is incompatible because upper bounds of type parameters are different: + public final expect class C3 + +actual class C3 + ^ +compiler/testData/multiplatform/incompatibleClasses/jvm.kt:18:20: error: actual typealias 'C4' has no corresponding expected declaration +The following declaration is incompatible because upper bounds of type parameters are different: + public final expect class C4 + +actual typealias C4 = C4Impl + ^ compiler/testData/multiplatform/incompatibleClasses/jvm.kt:21:39: error: actual class 'ExtendsNumber' has no corresponding expected declaration The following declaration is incompatible because some supertypes are missing in the actual declaration: public abstract expect class ExtendsNumber : Number diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index edab56422e5..ea1aa8f1936 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -14290,11 +14290,29 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/generic"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("functionTypeParameterBounds.kt") + public void testFunctionTypeParameterBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.kt"); + doTest(fileName); + } + + @TestMetadata("genericMemberBounds.kt") + public void testGenericMemberBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.kt"); + doTest(fileName); + } + @TestMetadata("membersInGenericClass.kt") public void testMembersInGenericClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.kt"); doTest(fileName); } + + @TestMetadata("typeParameterBoundsDifferentOrderActualMissing.kt") + public void testTypeParameterBoundsDifferentOrderActualMissing() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/headerClass") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index f832a168af9..f070b5d9bca 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -14290,11 +14290,29 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/generic"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("functionTypeParameterBounds.kt") + public void testFunctionTypeParameterBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/functionTypeParameterBounds.kt"); + doTest(fileName); + } + + @TestMetadata("genericMemberBounds.kt") + public void testGenericMemberBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/genericMemberBounds.kt"); + doTest(fileName); + } + @TestMetadata("membersInGenericClass.kt") public void testMembersInGenericClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.kt"); doTest(fileName); } + + @TestMetadata("typeParameterBoundsDifferentOrderActualMissing.kt") + public void testTypeParameterBoundsDifferentOrderActualMissing() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/typeParameterBoundsDifferentOrderActualMissing.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/headerClass")