diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 7eefcfa99a3..b13e570bf6b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -21228,6 +21228,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(fir|ll)\\.kts?$"), true); } + @Test + @TestMetadata("expectAndActualInSameModule.kt") + public void testExpectAndActualInSameModule() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt"); + } + @Test @TestMetadata("expectDataObject.kt") public void testExpectDataObject() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index e90f86e5820..c87d4985c01 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -21234,6 +21234,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(fir|ll)\\.kts?$"), true); } + @Test + @TestMetadata("expectAndActualInSameModule.kt") + public void testExpectAndActualInSameModule() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt"); + } + @Test @TestMetadata("expectDataObject.kt") public void testExpectDataObject() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index ef88d2e3e61..d0c7379b960 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -21228,6 +21228,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(fir|ll)\\.kts?$"), true); } + @Test + @TestMetadata("expectAndActualInSameModule.kt") + public void testExpectAndActualInSameModule() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt"); + } + @Test @TestMetadata("expectDataObject.kt") public void testExpectDataObject() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 25cb21b9142..374a5cfdc68 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -805,6 +805,8 @@ public interface Errors { DiagnosticFactory2.create(ERROR, ACTUAL_DECLARATION_NAME); DiagnosticFactory0 ACTUAL_MISSING = DiagnosticFactory0.create(ERROR, ACTUAL_DECLARATION_NAME); + DiagnosticFactory0 EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE = DiagnosticFactory0.create(WARNING, DECLARATION_NAME); + DiagnosticFactory0 OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index df65ee19ef9..03379e6acc1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -339,6 +339,7 @@ public class DefaultErrorMessages { MAP.put(NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, "Actual class ''{0}'' has no corresponding members for expected class members:{1}", NAME, adaptGenerics2(IncompatibleExpectedActualClassScopesRenderer.TEXT)); MAP.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'"); + MAP.put(EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE, "Expect and corresponding actual are declared in the same module, which will be prohibited in Kotlin 2.0. See https://youtrack.jetbrains.com/issue/KT-55177"); MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class"); MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry"); 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 012b3666f69..b090f8f281d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -181,27 +181,46 @@ class ExpectedActualDeclarationChecker( } // Here we have exactly one compatible actual and/or some weakly incompatible. In either case, we don't report anything on expect... - val actualMembers = actuals.asSequence() - .filter { it.key.isCompatibleOrWeakCompatible() }.flatMap { it.value.asSequence() } + val actualMembers = actuals.filter { it.key.isCompatibleOrWeakCompatible() }.flatMap { it.value } // ...except diagnostics regarding missing actual keyword, because in that case we won't start looking for the actual at all if (checkActualModifier) { actualMembers.forEach { reportMissingActualModifier(it, reportOn = null, trace) } } + reportExpectAndActualInTheSameModule(reportOn, actualMembers, trace) + expectActualTracker.reportExpectActual(expected = expectDescriptor, actualMembers = actualMembers) } private fun reportMissingActualModifier(actual: MemberDescriptor, reportOn: KtNamedDeclaration?, trace: BindingTrace) { if (actual.isActual) return @Suppress("NAME_SHADOWING") - val reportOn = reportOn ?: (actual.source as? KotlinSourceElement)?.psi as? KtNamedDeclaration ?: return + val reportOn = reportOn ?: actual.declarationSource ?: return if (requireActualModifier(actual)) { trace.report(Errors.ACTUAL_MISSING.on(reportOn)) } } + private val MemberDescriptor.declarationSource: KtNamedDeclaration? + get() = (this.source as? KotlinSourceElement)?.psi as? KtNamedDeclaration + + private fun reportExpectAndActualInTheSameModule( + expectSource: KtNamedDeclaration, + actualMembers: List, + trace: BindingTrace + ) { + if (expectSource.containingKtFile.isCommonSource == true) return + val actualMembersWithModifier = actualMembers.filter { it.isActual } + if (actualMembersWithModifier.isEmpty()) return + trace.report(Errors.EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE.on(expectSource)) + for (actual in actualMembersWithModifier) { + val actualSource = actual.declarationSource ?: continue + trace.report(Errors.EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE.on(actualSource)) + } + } + private fun MemberDescriptor.hasNoActualWithDiagnostic( compatibility: Map, List> ): Boolean { @@ -211,7 +230,7 @@ class ExpectedActualDeclarationChecker( } } - private fun ExpectActualTracker.reportExpectActual(expected: MemberDescriptor, actualMembers: Sequence) { + private fun ExpectActualTracker.reportExpectActual(expected: MemberDescriptor, actualMembers: List) { if (this is ExpectActualTracker.DoNothing) return val expectedFile = sourceFile(expected) ?: return diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv14.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv14.kt index 1584cbb7b84..50633ab4ccc 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv14.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv14.kt @@ -1,3 +1,5 @@ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") + package test @Suppress("INLINE_CLASS_DEPRECATED", "EXPERIMENTAL_FEATURE_WARNING") diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv15.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv15.kt index fd0a542f705..71d80a26d81 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv15.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/actualTypealiasToCompiledInlineClass/expectActualLv15.kt @@ -1,3 +1,5 @@ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") + package test @kotlin.jvm.JvmInline diff --git a/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.fir.kt b/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.fir.kt new file mode 100644 index 00000000000..ea703db9269 --- /dev/null +++ b/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.fir.kt @@ -0,0 +1,10 @@ +// !LANGUAGE: +MultiPlatformProjects +// SKIP_TXT +// Issue: KT-49714 + +expect class Counter { + operator fun inc(): Counter + operator fun dec(): Counter +} + +actual typealias Counter = Int \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.kt b/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.kt index cb90b5e2b99..c69d5072e23 100644 --- a/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.kt +++ b/compiler/testData/diagnostics/tests/IncDecOperatorsInExpectClass.kt @@ -1,11 +1,10 @@ -// FIR_IDENTICAL // !LANGUAGE: +MultiPlatformProjects // SKIP_TXT // Issue: KT-49714 -expect class Counter { +expect class Counter { operator fun inc(): Counter operator fun dec(): Counter } -actual typealias Counter = Int +actual typealias Counter = Int diff --git a/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.fir.kt new file mode 100644 index 00000000000..50201b6d3e0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.fir.kt @@ -0,0 +1,17 @@ +// ISSUE: KT-40904, KT-55177 + +expect class Foo { + fun memberFun() + val memberProp: Int +} +actual class Foo { + actual fun memberFun() {} + actual val memberProp: Int = 10 +} + +expect fun foo() +actual fun foo() {} + +expect val x: String +actual val x: String + get() = "hello" diff --git a/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt b/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt new file mode 100644 index 00000000000..2b9810c054a --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt @@ -0,0 +1,17 @@ +// ISSUE: KT-40904, KT-55177 + +expect class Foo { + fun memberFun() + val memberProp: Int +} +actual class Foo { + actual fun memberFun() {} + actual val memberProp: Int = 10 +} + +expect fun foo() +actual fun foo() {} + +expect val x: String +actual val x: String + get() = "hello" diff --git a/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.txt b/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.txt new file mode 100644 index 00000000000..adc433e97e2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.txt @@ -0,0 +1,14 @@ +package + +public actual val x: kotlin.String +public actual fun foo(): kotlin.Unit + +public final actual class Foo { + public constructor Foo() + public actual final val memberProp: kotlin.Int = 10 + 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 final actual fun memberFun(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + 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 d05a466970b..24668d51b43 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 @@ -21234,6 +21234,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(fir|ll)\\.kts?$"), true); } + @Test + @TestMetadata("expectAndActualInSameModule.kt") + public void testExpectAndActualInSameModule() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/expectAndActualInSameModule.kt"); + } + @Test @TestMetadata("expectDataObject.kt") public void testExpectDataObject() throws Exception { diff --git a/libraries/stdlib/common/test/jsCollectionFactories.kt b/libraries/stdlib/common/test/jsCollectionFactories.kt index 47d5e8a665b..e12aef2a8d0 100644 --- a/libraries/stdlib/common/test/jsCollectionFactories.kt +++ b/libraries/stdlib/common/test/jsCollectionFactories.kt @@ -2,6 +2,7 @@ * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") package test.collections.js diff --git a/libraries/stdlib/common/test/testUtils.kt b/libraries/stdlib/common/test/testUtils.kt index 9b5ffaf3ee8..1ac998dda47 100644 --- a/libraries/stdlib/common/test/testUtils.kt +++ b/libraries/stdlib/common/test/testUtils.kt @@ -2,6 +2,7 @@ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") package test @@ -33,4 +34,4 @@ public expect object BackReferenceHandling { val nonExistentGroup: HandlingOption val nonExistentNamedGroup: HandlingOption val groupZero: HandlingOption -} \ No newline at end of file +} diff --git a/libraries/stdlib/jvm/test/js/StubsJVM.kt b/libraries/stdlib/jvm/test/js/StubsJVM.kt index 0fd5c148140..36e3e7ccf09 100644 --- a/libraries/stdlib/jvm/test/js/StubsJVM.kt +++ b/libraries/stdlib/jvm/test/js/StubsJVM.kt @@ -2,6 +2,7 @@ * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") package test.collections.js diff --git a/libraries/stdlib/jvm/test/testUtilsJVM.kt b/libraries/stdlib/jvm/test/testUtilsJVM.kt index 22a7d06535d..ac503baec8d 100644 --- a/libraries/stdlib/jvm/test/testUtilsJVM.kt +++ b/libraries/stdlib/jvm/test/testUtilsJVM.kt @@ -2,6 +2,7 @@ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") package test @@ -38,4 +39,4 @@ public actual object BackReferenceHandling { actual val nonExistentGroup: HandlingOption = HandlingOption.MATCH_NOTHING actual val nonExistentNamedGroup: HandlingOption = HandlingOption.THROW actual val groupZero: HandlingOption = HandlingOption.THROW -} \ No newline at end of file +}