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 2166e4d9a8c..a611748b6e4 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 @@ -287,9 +287,9 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst } @Test - @TestMetadata("optionalExpectation.kt") - public void testOptionalExpectation() throws Exception { - runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); + @TestMetadata("skippedAnnotations.kt") + public void testSkippedAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/skippedAnnotations.kt"); } @Test 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 ba4c6c07833..10e11534929 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 @@ -287,9 +287,9 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi } @Test - @TestMetadata("optionalExpectation.kt") - public void testOptionalExpectation() throws Exception { - runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); + @TestMetadata("skippedAnnotations.kt") + public void testSkippedAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/skippedAnnotations.kt"); } @Test diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt index c01a56eda4f..f16871c5d7c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo +import org.jetbrains.kotlin.resolve.checkers.OptInNames import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.Variance @@ -357,6 +358,9 @@ class FirExpectActualMatchingContextImpl private constructor( override val isRetentionSource: Boolean get() = getAnnotationClass()?.getRetention(actualSession) == AnnotationRetention.SOURCE + override val isOptIn: Boolean + get() = getAnnotationClass()?.hasAnnotation(OptInNames.REQUIRES_OPT_IN_CLASS_ID, actualSession) ?: false + private fun getAnnotationClass(): FirRegularClassSymbol? = annotation.annotationTypeRef.coneType.toRegularClassSymbol(actualSession) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt index 056f71c03be..0c585187d11 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo +import org.jetbrains.kotlin.resolve.checkers.OptInNames import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.Variance @@ -467,10 +468,14 @@ internal abstract class IrExpectActualMatchingContext( get() = irElement.type.getClass()?.classId override val isRetentionSource: Boolean - get() { - val annotationClass = irElement.symbol.owner.parent as? IrClass ?: return false - return annotationClass.getAnnotationRetention() == KotlinRetention.SOURCE - } + get() = getAnnotationClass()?.getAnnotationRetention() == KotlinRetention.SOURCE + + override val isOptIn: Boolean + get() = getAnnotationClass()?.hasAnnotation(OptInNames.REQUIRES_OPT_IN_FQ_NAME) ?: false + + private fun getAnnotationClass(): IrClass? { + return irElement.symbol.owner.parent as? IrClass + } } override val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean 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 b124971bd3f..a04a845851f 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 @@ -10,6 +10,16 @@ import org.jetbrains.kotlin.mpp.TypeAliasSymbolMarker import org.jetbrains.kotlin.name.StandardClassIds object AbstractExpectActualAnnotationMatchChecker { + private val SKIPPED_CLASS_IDS = setOf( + StandardClassIds.Annotations.Deprecated, + StandardClassIds.Annotations.DeprecatedSinceKotlin, + StandardClassIds.Annotations.OptionalExpectation, + StandardClassIds.Annotations.RequireKotlin, + StandardClassIds.Annotations.SinceKotlin, + StandardClassIds.Annotations.Suppress, + StandardClassIds.Annotations.WasExperimental, + ) + class Incompatibility(val expectSymbol: DeclarationSymbolMarker, val actualSymbol: DeclarationSymbolMarker) fun areAnnotationsCompatible( @@ -36,7 +46,7 @@ object AbstractExpectActualAnnotationMatchChecker { val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId } for (expectAnnotation in expectSymbol.annotations) { - if (expectAnnotation.classId == StandardClassIds.Annotations.OptionalExpectation) { + if (expectAnnotation.classId in SKIPPED_CLASS_IDS || expectAnnotation.isOptIn) { continue } if (expectAnnotation.isRetentionSource && skipSourceAnnotations) { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt index b719dab61e0..65c984e4606 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt @@ -167,5 +167,6 @@ interface ExpectActualMatchingContext : TypeSystemC interface AnnotationCallInfo { val classId: ClassId? val isRetentionSource: Boolean + val isOptIn: Boolean } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt index c38e728e336..bc607e98118 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo +import org.jetbrains.kotlin.resolve.checkers.OptInNames import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -351,6 +352,9 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) : override val isRetentionSource: Boolean get() = annotationDescriptor.isSourceAnnotation + + override val isOptIn: Boolean + get() = annotationDescriptor.annotationClass?.annotations?.hasAnnotation(OptInNames.REQUIRES_OPT_IN_FQ_NAME) ?: false } override val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt deleted file mode 100644 index 2e53bf3d47d..00000000000 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt +++ /dev/null @@ -1,12 +0,0 @@ -// FIR_IDENTICAL -// WITH_STDLIB -// MODULE: m1-common -// FILE: common.kt -@OptIn(ExperimentalMultiplatform::class) -@OptionalExpectation -expect annotation class MyAnnotation - -// MODULE: m1-jvm()()(m1-common) -// FILE: jvm.kt -@OptIn(ExperimentalMultiplatform::class) -actual annotation class MyAnnotation diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/skippedAnnotations.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/skippedAnnotations.kt new file mode 100644 index 00000000000..2fcfe73d38a --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/skippedAnnotations.kt @@ -0,0 +1,30 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +package kotlin + +@OptIn(ExperimentalMultiplatform::class) +@OptionalExpectation +expect annotation class OptionalExpectationOnExpectOnly + +@RequiresOptIn +annotation class MyOptIn + +@SinceKotlin("1.8") +@Deprecated(message = "Some text") +@DeprecatedSinceKotlin("1.8") +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +@MyOptIn +@WasExperimental(MyOptIn::class) +@kotlin.internal.RequireKotlin(version = "1.8") +expect fun skippedAnnotationsOnExpectOnly() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +package kotlin + +@OptIn(ExperimentalMultiplatform::class) +actual annotation class OptionalExpectationOnExpectOnly + +actual fun skippedAnnotationsOnExpectOnly() {} \ No newline at end of file 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 fc5431d771a..189d6075b71 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 @@ -22832,9 +22832,9 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } @Test - @TestMetadata("optionalExpectation.kt") - public void testOptionalExpectation() throws Exception { - runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); + @TestMetadata("skippedAnnotations.kt") + public void testSkippedAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/skippedAnnotations.kt"); } @Test diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index b52562f4aa0..6c83c62c844 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -153,6 +153,7 @@ object StandardClassIds { val ContextFunctionTypeParams = "ContextFunctionTypeParams".baseId() val Deprecated = "Deprecated".baseId() val DeprecatedSinceKotlin = "DeprecatedSinceKotlin".baseId() + val RequireKotlin = "RequireKotlin".internalId() val HidesMembers = "HidesMembers".internalId() val DynamicExtension = "DynamicExtension".internalId()