diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java index 1ffcb6cdd8e..623debfbcca 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java @@ -414,6 +414,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFinalActualOpen.kt"); } + @Test + @TestMetadata("expectFunInterface.kt") + public void testExpectFunInterface() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFunInterface.kt"); + } + @Test @TestMetadata("explicitConstructorDelegation.kt") public void testExplicitConstructorDelegation() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index b09ae473ae0..765e69ef2b7 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java @@ -414,6 +414,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFinalActualOpen.kt"); } + @Test + @TestMetadata("expectFunInterface.kt") + public void testExpectFunInterface() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFunInterface.kt"); + } + @Test @TestMetadata("explicitConstructorDelegation.kt") public void testExplicitConstructorDelegation() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt index 46d8b231a3c..f10c052cda7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt @@ -123,6 +123,9 @@ object FirExpectActualResolver { if (!equalBy(expectClassSymbol, actualClass) { listOf(it.isCompanion, it.isInner, it.isInline /*|| it.isValue*/) }) { return ExpectActualCompatibility.Incompatible.ClassModifiers } + if (expectClassSymbol.isFun && !actualClass.isFun) { + return ExpectActualCompatibility.Incompatible.FunInterfaceModifier + } val expectTypeParameterSymbols = expectClassSymbol.typeParameterSymbols val actualTypeParameterSymbols = actualClass.typeParameterSymbols diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/ClassicPositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/ClassicPositioningStrategies.kt index ff46343862d..cdf9abac561 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/ClassicPositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/ClassicPositioningStrategies.kt @@ -90,7 +90,8 @@ object ClassicPositioningStrategies { ExpectActualCompatibility.Incompatible.FunctionModifiersNotSubset, ExpectActualCompatibility.Incompatible.PropertyLateinitModifier, ExpectActualCompatibility.Incompatible.PropertyConstModifier, - ExpectActualCompatibility.Incompatible.ClassModifiers -> { + ExpectActualCompatibility.Incompatible.ClassModifiers, + ExpectActualCompatibility.Incompatible.FunInterfaceModifier -> { element.modifierList } ExpectActualCompatibility.Incompatible.PropertyKind -> { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt index 43a527efd3d..b1df5dcd167 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt @@ -387,6 +387,9 @@ object ExpectedActualResolver { if (a.kind != b.kind) return Incompatible.ClassKind if (!equalBy(a, b) { listOf(it.isCompanionObject, it.isInner, it.isInline || it.isValue) }) return Incompatible.ClassModifiers + if (a.isFun && !b.isFun && b.isNotJavaSamInterface()) { + return Incompatible.FunInterfaceModifier + } val aTypeParams = a.declaredTypeParameters val bTypeParams = b.declaredTypeParameters @@ -563,3 +566,7 @@ fun DeclarationDescriptor.findActuals(inModule: ModuleDescriptor): Listactual interface F2 { + actual fun run() +} + +actual typealias F3 = java.lang.Runnable + +actual fun interface F4 { + actual fun run() +} + +fun interface F5Typealias { + fun run() +} + +actual typealias F5 = F5Typealias + +interface F6Typealias { + fun run() +} + +actual typealias F6 = F6Typealias diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFunInterface.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFunInterface.kt new file mode 100644 index 00000000000..8dc49612f35 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFunInterface.kt @@ -0,0 +1,54 @@ +// MODULE: m1-common +// FILE: common.kt + +expect fun interface F1 { + fun run() +} + +expect fun interface F2 { + fun run() +} + +expect fun interface F3 { + fun run() +} + +expect interface F4 { + fun run() +} + +expect fun interface F5 { + fun run() +} + +expect fun interface F6 { + fun run() +} + +// MODULE: m2-jvm()()(m1-common) + +actual fun interface F1 { + actual fun run() +} + +actual interface F2 { + actual fun run() +} + +actual typealias F3 = java.lang.Runnable + +actual fun interface F4 { + actual fun run() +} + +fun interface F5Typealias { + fun run() +} + +actual typealias F5 = F5Typealias + +interface F6Typealias { + fun run() +} + +actual typealias F6 = F6Typealias \ No newline at end of file diff --git a/compiler/testData/multiplatform/incompatibleClasses/common.kt b/compiler/testData/multiplatform/incompatibleClasses/common.kt index c4516abc934..5b7f7041d73 100644 --- a/compiler/testData/multiplatform/incompatibleClasses/common.kt +++ b/compiler/testData/multiplatform/incompatibleClasses/common.kt @@ -19,3 +19,11 @@ expect class C4 expect abstract class ExtendsNumber : Number + +expect fun interface FunInterface { + fun run() +} + +expect fun interface FunInterface2 { + fun run() +} diff --git a/compiler/testData/multiplatform/incompatibleClasses/jvm.kt b/compiler/testData/multiplatform/incompatibleClasses/jvm.kt index b8f9716dd1b..5d12737acd0 100644 --- a/compiler/testData/multiplatform/incompatibleClasses/jvm.kt +++ b/compiler/testData/multiplatform/incompatibleClasses/jvm.kt @@ -19,3 +19,13 @@ actual typealias C4 = C4Impl class C4Impl actual abstract class ExtendsNumber : Any() + +actual interface FunInterface { + actual fun run() +} + +interface FunInterface2Typealias { + fun run() +} + +actual typealias FunInterface2 = FunInterface2Typealias \ No newline at end of file diff --git a/compiler/testData/multiplatform/incompatibleClasses/output.txt b/compiler/testData/multiplatform/incompatibleClasses/output.txt index 0ee676c7567..9703ce14f65 100644 --- a/compiler/testData/multiplatform/incompatibleClasses/output.txt +++ b/compiler/testData/multiplatform/incompatibleClasses/output.txt @@ -113,3 +113,15 @@ The following declaration is incompatible because some supertypes are missing in actual abstract class ExtendsNumber : Any() ^ +compiler/testData/multiplatform/incompatibleClasses/jvm.kt:23:1: error: actual interface 'FunInterface' has no corresponding expected declaration +The following declaration is incompatible because actual declaration for fun expect interface is not a functional interface: + public expect fun interface FunInterface + +actual interface FunInterface { +^ +compiler/testData/multiplatform/incompatibleClasses/jvm.kt:31:1: error: actual typealias 'FunInterface2' has no corresponding expected declaration +The following declaration is incompatible because actual declaration for fun expect interface is not a functional interface: + public expect fun interface FunInterface2 + +actual typealias FunInterface2 = FunInterface2Typealias +^ diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 724942b2387..283d79e1c74 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -22193,6 +22193,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFinalActualOpen.kt"); } + @Test + @TestMetadata("expectFunInterface.kt") + public void testExpectFunInterface() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/expectFunInterface.kt"); + } + @Test @TestMetadata("explicitConstructorDelegation.kt") public void testExplicitConstructorDelegation() throws Exception { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt b/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt index 8a8287216a6..948d2b00cfc 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt @@ -65,6 +65,8 @@ sealed class ExpectActualCompatibility { object ClassModifiers : Incompatible("modifiers are different (companion, inner, inline)") + object FunInterfaceModifier : Incompatible("actual declaration for fun expect interface is not a functional interface") + object Supertypes : Incompatible("some supertypes are missing in the actual declaration") class ClassScopes(