From 8fb2935ef634c688ee342d1284d03591802fd43f Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 2 Aug 2023 15:18:58 +0200 Subject: [PATCH] [FE, IR] Check annotations compatibility on expect and actual type parameters ^KT-60671 --- ...DiagnosticsWithLightTreeTestGenerated.java | 6 ++++ ...endMPPDiagnosticsWithPsiTestGenerated.java | 6 ++++ ...tractExpectActualAnnotationMatchChecker.kt | 26 ++++++++++++++ .../checkDiagnosticFullText.diag.txt | 16 +++++---- .../checkDiagnosticFullText.fir.diag.txt | 15 ++++---- .../checkDiagnosticFullText.fir.kt | 10 ++++++ .../checkDiagnosticFullText.kt | 10 ++++++ .../annotationMatching/typeParameters.fir.kt | 34 +++++++++++++++++++ .../annotationMatching/typeParameters.kt | 34 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 ++++ 10 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt 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 6be983aec34..7a0f121fe22 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 @@ -908,6 +908,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/twoActualTypealiasesToSameClass.kt"); } + @Test + @TestMetadata("typeParameters.kt") + public void testTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt"); + } + @Test @TestMetadata("typealias.kt") public void testTypealias() 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 22c34459a89..42dfbeb5f7b 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 @@ -908,6 +908,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/twoActualTypealiasesToSameClass.kt"); } + @Test + @TestMetadata("typeParameters.kt") + public void testTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt"); + } + @Test @TestMetadata("typealias.kt") public void testTypealias() throws Exception { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt index 8ecab52cd8d..63cac75f9f5 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt @@ -112,6 +112,7 @@ object AbstractExpectActualAnnotationMatchChecker { actualSymbol: DeclarationSymbolMarker, ): Incompatibility? { areAnnotationsSetOnDeclarationsCompatible(expectSymbol, actualSymbol)?.let { return it } + areAnnotationsOnTypeParametersCompatible(expectSymbol, actualSymbol)?.let { return it } return null } @@ -134,6 +135,31 @@ object AbstractExpectActualAnnotationMatchChecker { } } + context (ExpectActualMatchingContext<*>) + private fun areAnnotationsOnTypeParametersCompatible( + expectSymbol: DeclarationSymbolMarker, + actualSymbol: DeclarationSymbolMarker, + ): Incompatibility? { + fun DeclarationSymbolMarker.getTypeParameters(): List? { + return when (this) { + is FunctionSymbolMarker -> typeParameters + is RegularClassSymbolMarker -> typeParameters + else -> null + } + } + + val expectParams = expectSymbol.getTypeParameters() ?: return null + val actualParams = actualSymbol.getTypeParameters() ?: return null + if (expectParams.size != actualParams.size) return null + + return expectParams.zip(actualParams).firstNotNullOfOrNull { (expectParam, actualParam) -> + areAnnotationsSetOnDeclarationsCompatible(expectParam, actualParam)?.let { + // Write containing declarations into diagnostic + Incompatibility(expectSymbol, actualSymbol, actualParam.getSourceElement(), it.type) + } + } + } + context (ExpectActualMatchingContext<*>) private fun areAnnotationsSetOnDeclarationsCompatible( expectSymbol: DeclarationSymbolMarker, diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt index 97ee54f26b9..31ba12080f8 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt @@ -1,28 +1,32 @@ // -- Module: -- // -- Module: -- -/jvm.kt:31:14: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:39:14: warning: annotation `@Ann` is missing on actual declaration. All annotations from expect `class OnClass defined in root package in file common.kt` must be present with the same arguments on actual `class OnClass defined in root package in file jvm.kt`, otherwise they might behave incorrectly. actual class OnClass ^ -/jvm.kt:34:16: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:42:16: warning: annotation `@Ann` is missing on actual declaration. All annotations from expect `fun onMember(): Unit defined in OnMember` must be present with the same arguments on actual `fun onMember(): Unit defined in OnMember`, otherwise they might behave incorrectly. actual fun onMember() {} ^ -/jvm.kt:39:18: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:47:18: warning: annotation `@Ann` is missing on actual declaration. All annotations from expect `class ViaTypealias defined in root package in file common.kt` must be present with the same arguments on actual `class ViaTypealiasImpl defined in root package in file jvm.kt`, otherwise they might behave incorrectly. actual typealias ViaTypealias = ViaTypealiasImpl ^ -/jvm.kt:44:18: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:52:18: warning: annotation `@Ann` is missing on actual declaration. All annotations from expect `fun foo(): Unit defined in MemberScopeViaTypealias` must be present with the same arguments on actual `fun foo(): Unit defined in MemberScopeViaTypealiasImpl`, otherwise they might behave incorrectly. actual typealias MemberScopeViaTypealias = MemberScopeViaTypealiasImpl ^ -/jvm.kt:47:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`. +/jvm.kt:55:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`. All annotations from expect `fun withDifferentArg(): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun withDifferentArg(): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly. actual fun withDifferentArg() {} ^ -/jvm.kt:49:12: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:57:12: warning: annotation `@Ann` is missing on actual declaration. All annotations from expect `fun inValueParam(arg: String): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun inValueParam(arg: String): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly. actual fun inValueParam(arg: String) {} ^ +/jvm.kt:59:16: warning: annotation `@Ann` is missing on actual declaration. +All annotations from expect `fun inTypeParam(): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun inTypeParam(): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly. +actual fun inTypeParam() {} + ^ diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt index f03b1674954..f45301fd11d 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt @@ -1,17 +1,20 @@ -/jvm.kt:(90,97): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(98,105): warning: Annotation `@Ann()` is missing on actual declaration. All annotations from expect 'class OnClass : Any' must be present with the same arguments on actual 'class OnClass : Any', otherwise they might behave incorrectly. -/jvm.kt:(138,146): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(146,154): warning: Annotation `@Ann()` is missing on actual declaration. All annotations from expect 'fun onMember(): Unit' must be present with the same arguments on actual 'fun onMember(): Unit', otherwise they might behave incorrectly. -/jvm.kt:(196,208): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(204,216): warning: Annotation `@Ann()` is missing on actual declaration. All annotations from expect 'class ViaTypealias : Any' must be present with the same arguments on actual 'class ViaTypealiasImpl : Any', otherwise they might behave incorrectly. -/jvm.kt:(301,324): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(309,332): warning: Annotation `@Ann()` is missing on actual declaration. All annotations from expect 'fun foo(): Unit' must be present with the same arguments on actual 'fun foo(): Unit', otherwise they might behave incorrectly. -/jvm.kt:(389,405): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`. +/jvm.kt:(397,413): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`. All annotations from expect 'fun withDifferentArg(): Unit' must be present with the same arguments on actual 'fun withDifferentArg(): Unit', otherwise they might behave incorrectly. -/jvm.kt:(423,435): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(431,443): warning: Annotation `@Ann()` is missing on actual declaration. All annotations from expect 'fun inValueParam(arg: String): Unit' must be present with the same arguments on actual 'fun inValueParam(arg: String): Unit', otherwise they might behave incorrectly. + +/jvm.kt:(476,487): warning: Annotation `@Ann()` is missing on actual declaration. +All annotations from expect 'fun inTypeParam(): Unit' must be present with the same arguments on actual 'fun inTypeParam(): Unit', otherwise they might behave incorrectly. diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt index a455012e5fd..4b62c27d8b6 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt @@ -1,6 +1,12 @@ // RENDER_DIAGNOSTICS_FULL_TEXT // MODULE: m1-common // FILE: common.kt +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.CLASS, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.TYPE_PARAMETER, +) annotation class Ann @Ann @@ -26,6 +32,8 @@ expect fun withDifferentArg() expect fun inValueParam(@Ann arg: String) +expect fun <@Ann T> inTypeParam() + // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual class OnClass @@ -47,3 +55,5 @@ class MemberScopeViaTypealiasImpl { actual fun withDifferentArg() {} actual fun inValueParam(arg: String) {} + +actual fun inTypeParam() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt index a9219fe1e95..68cd1361dd1 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt @@ -1,6 +1,12 @@ // RENDER_DIAGNOSTICS_FULL_TEXT // MODULE: m1-common // FILE: common.kt +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.CLASS, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.TYPE_PARAMETER, +) annotation class Ann @Ann @@ -26,6 +32,8 @@ expect fun withDifferentArg() expect fun inValueParam(@Ann arg: String) +expect fun <@Ann T> inTypeParam() + // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual class OnClass @@ -47,3 +55,5 @@ actual typealias MemberScopeViaTypealias< actual fun withDifferentArg() {} actual fun inValueParam(arg: String) {} + +actual fun inTypeParam() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.fir.kt new file mode 100644 index 00000000000..966300aef1f --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.fir.kt @@ -0,0 +1,34 @@ +// MODULE: m1-common +// FILE: common.kt +@Target(AnnotationTarget.TYPE_PARAMETER) +annotation class Ann + +expect fun <@Ann A> inMethod() + +expect fun inMethodTwoParams() + +expect class InClass<@Ann A> + +expect class ViaTypealias<@Ann A> + +expect class TypealiasParamNotAccepted<@Ann A> + +expect fun <@Ann A, @Ann B> withIncompatibility() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual fun inMethod() {} + +actual fun <@Ann A, B> inMethodTwoParams() {} + +actual class InClass + +class ViaTypealiasImpl<@Ann A> + +actual typealias ViaTypealias = ViaTypealiasImpl + +class TypealiasParamNotAcceptedImpl + +actual typealias TypealiasParamNotAccepted<@Ann A> = TypealiasParamNotAcceptedImpl + +actual fun withIncompatibility() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt new file mode 100644 index 00000000000..b20d49c874a --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt @@ -0,0 +1,34 @@ +// MODULE: m1-common +// FILE: common.kt +@Target(AnnotationTarget.TYPE_PARAMETER) +annotation class Ann + +expect fun <@Ann A> inMethod() + +expect fun inMethodTwoParams() + +expect class InClass<@Ann A> + +expect class ViaTypealias<@Ann A> + +expect class TypealiasParamNotAccepted<@Ann A> + +expect fun <@Ann A, @Ann B> withIncompatibility() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual fun inMethod() {} + +actual fun <@Ann A, B> inMethodTwoParams() {} + +actual class InClass + +class ViaTypealiasImpl<@Ann A> + +actual typealias ViaTypealias = ViaTypealiasImpl + +class TypealiasParamNotAcceptedImpl + +actual typealias TypealiasParamNotAccepted<@Ann A> = TypealiasParamNotAcceptedImpl + +actual fun withIncompatibility() {} 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 327dc132c44..bd8ca85a8da 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 @@ -23903,6 +23903,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/twoActualTypealiasesToSameClass.kt"); } + @Test + @TestMetadata("typeParameters.kt") + public void testTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typeParameters.kt"); + } + @Test @TestMetadata("typealias.kt") public void testTypealias() throws Exception {