From 1a4ab9bb4b2034e4a792e6714c322010a060d4d3 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Thu, 22 Jun 2023 15:22:17 +0200 Subject: [PATCH] [FE] Implement FE logic of expect actual annotations matching This implementation only checks annotations set on expect/actual declarations and requires further refinement (e.g. checking of other annotation targets, class scopes within typealiases). ^KT-58551 --- .../diagnostics/KtFirDataClassConverters.kt | 8 + .../api/fir/diagnostics/KtFirDiagnostics.kt | 6 + .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 + ...DiagnosticsWithLightTreeTestGenerated.java | 94 ++++++++++++ ...endMPPDiagnosticsWithPsiTestGenerated.java | 94 ++++++++++++ .../diagnostics/FirDiagnosticsList.kt | 5 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../FirExpectActualDeclarationChecker.kt | 31 +++- .../diagnostics/FirDiagnosticRenderers.kt | 10 ++ .../diagnostics/FirErrorsDefaultMessages.kt | 8 + .../mpp/FirExpectActualMatchingContextImpl.kt | 52 ++++++- .../jetbrains/kotlin/diagnostics/Errors.java | 2 + .../rendering/DefaultErrorMessages.java | 5 + .../kotlin/diagnostics/rendering/Renderers.kt | 10 ++ .../ExpectedActualDeclarationChecker.kt | 23 ++- .../IrExpectActualMatchingContext.kt | 16 +- ...tractExpectActualAnnotationMatchChecker.kt | 40 +++++ .../calls/mpp/ExpectActualMatchingContext.kt | 9 ++ .../ClassicExpectActualMatchingContext.kt | 24 ++- .../constExpressionValuesEqualityChecker.kt | 33 +++++ ...annotationArgumentsConstExpressions.fir.kt | 138 ++++++++++++++++++ .../annotationArgumentsConstExpressions.kt | 138 ++++++++++++++++++ .../annotationArgumentsDefaults.kt | 12 ++ .../annotationTypeParameters.fir.kt | 101 +++++++++++++ .../annotationTypeParameters.kt | 101 +++++++++++++ .../annotationMatching/basicOnDeclaration.kt | 42 ++++++ .../checkDiagnosticFullText.diag.txt | 19 +++ .../checkDiagnosticFullText.fir.diag.txt | 11 ++ .../checkDiagnosticFullText.kt | 34 +++++ .../annotationMatching/compatibleOverrides.kt | 19 +++ .../annotationMatching/differentOrder.fir.kt | 31 ++++ .../annotationMatching/differentOrder.kt | 31 ++++ .../floatNumbersComparison.fir.kt | 11 ++ .../floatNumbersComparison.kt | 11 ++ .../kclassArgWithExpectClass.kt | 35 +++++ .../kotlinAnaloguesForJavaAnnotations.kt | 29 ++++ .../annotationMatching/typealias.kt | 23 +++ .../typealiasToJavaLibrary.fir.kt | 14 ++ .../typealiasToJavaLibrary.kt | 14 ++ .../typealiasToKtLibrary.fir.kt | 32 ++++ .../typealiasToKtLibrary.kt | 32 ++++ .../withOtherIncomatibilities.fir.kt | 19 +++ .../withOtherIncomatibilities.kt | 19 +++ .../expectOptInAnnotation.fir.kt | 3 +- .../multiplatform/expectOptInAnnotation.kt | 3 +- .../optionalExpectation/common.kt | 4 +- .../multiplatform/optionalExpectation/js.kt | 3 - .../multiplatform/optionalExpectation/jvm.kt | 5 - .../test/runners/DiagnosticTestGenerated.java | 94 ++++++++++++ 49 files changed, 1481 insertions(+), 25 deletions(-) create mode 100644 compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt create mode 100644 compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/constExpressionValuesEqualityChecker.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 11dec691d7c..ca1bebd6154 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -3504,6 +3504,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT) { firDiagnostic -> + ActualAnnotationsNotMatchExpectImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a), + firSymbolBuilder.buildSymbol(firDiagnostic.b), + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION) { firDiagnostic -> InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic as KtPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 292c3857e9e..aa88cef8c1d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2448,6 +2448,12 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val typealiasedClassId: ClassId } + interface ActualAnnotationsNotMatchExpect : KtFirDiagnostic { + override val diagnosticClass get() = ActualAnnotationsNotMatchExpect::class + val expect: KtSymbol + val actual: KtSymbol + } + interface InitializerRequiredForDestructuringDeclaration : KtFirDiagnostic { override val diagnosticClass get() = InitializerRequiredForDestructuringDeclaration::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 7998c2b1133..745d8bcf9c3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2952,6 +2952,13 @@ internal class ActualTypealiasToSpecialAnnotationImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.ActualTypealiasToSpecialAnnotation +internal class ActualAnnotationsNotMatchExpectImpl( + override val expect: KtSymbol, + override val actual: KtSymbol, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.ActualAnnotationsNotMatchExpect + internal class InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic: KtPsiDiagnostic, token: KtLifetimeToken, 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 b2c7a185f36..503d5af805a 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 @@ -205,6 +205,100 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching") + @TestDataPath("$PROJECT_ROOT") + public class AnnotationMatching { + @Test + public void testAllFilesPresentInAnnotationMatching() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("annotationArgumentsConstExpressions.kt") + public void testAnnotationArgumentsConstExpressions() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt"); + } + + @Test + @TestMetadata("annotationArgumentsDefaults.kt") + public void testAnnotationArgumentsDefaults() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt"); + } + + @Test + @TestMetadata("annotationTypeParameters.kt") + public void testAnnotationTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt"); + } + + @Test + @TestMetadata("basicOnDeclaration.kt") + public void testBasicOnDeclaration() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt"); + } + + @Test + @TestMetadata("checkDiagnosticFullText.kt") + public void testCheckDiagnosticFullText() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt"); + } + + @Test + @TestMetadata("compatibleOverrides.kt") + public void testCompatibleOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt"); + } + + @Test + @TestMetadata("differentOrder.kt") + public void testDifferentOrder() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt"); + } + + @Test + @TestMetadata("floatNumbersComparison.kt") + public void testFloatNumbersComparison() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt"); + } + + @Test + @TestMetadata("kclassArgWithExpectClass.kt") + public void testKclassArgWithExpectClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt"); + } + + @Test + @TestMetadata("kotlinAnaloguesForJavaAnnotations.kt") + public void testKotlinAnaloguesForJavaAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt"); + } + + @Test + @TestMetadata("typealias.kt") + public void testTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt"); + } + + @Test + @TestMetadata("typealiasToJavaLibrary.kt") + public void testTypealiasToJavaLibrary() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt"); + } + + @Test + @TestMetadata("typealiasToKtLibrary.kt") + public void testTypealiasToKtLibrary() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt"); + } + + @Test + @TestMetadata("withOtherIncomatibilities.kt") + public void testWithOtherIncomatibilities() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments") @TestDataPath("$PROJECT_ROOT") 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 0e5b572d170..0accbe88a08 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 @@ -205,6 +205,100 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching") + @TestDataPath("$PROJECT_ROOT") + public class AnnotationMatching { + @Test + public void testAllFilesPresentInAnnotationMatching() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("annotationArgumentsConstExpressions.kt") + public void testAnnotationArgumentsConstExpressions() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt"); + } + + @Test + @TestMetadata("annotationArgumentsDefaults.kt") + public void testAnnotationArgumentsDefaults() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt"); + } + + @Test + @TestMetadata("annotationTypeParameters.kt") + public void testAnnotationTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt"); + } + + @Test + @TestMetadata("basicOnDeclaration.kt") + public void testBasicOnDeclaration() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt"); + } + + @Test + @TestMetadata("checkDiagnosticFullText.kt") + public void testCheckDiagnosticFullText() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt"); + } + + @Test + @TestMetadata("compatibleOverrides.kt") + public void testCompatibleOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt"); + } + + @Test + @TestMetadata("differentOrder.kt") + public void testDifferentOrder() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt"); + } + + @Test + @TestMetadata("floatNumbersComparison.kt") + public void testFloatNumbersComparison() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt"); + } + + @Test + @TestMetadata("kclassArgWithExpectClass.kt") + public void testKclassArgWithExpectClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt"); + } + + @Test + @TestMetadata("kotlinAnaloguesForJavaAnnotations.kt") + public void testKotlinAnaloguesForJavaAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt"); + } + + @Test + @TestMetadata("typealias.kt") + public void testTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt"); + } + + @Test + @TestMetadata("typealiasToJavaLibrary.kt") + public void testTypealiasToJavaLibrary() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt"); + } + + @Test + @TestMetadata("typealiasToKtLibrary.kt") + public void testTypealiasToKtLibrary() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt"); + } + + @Test + @TestMetadata("withOtherIncomatibilities.kt") + public void testWithOtherIncomatibilities() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index e8e7f091199..825d6edda5b 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -1180,6 +1180,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error(PositioningStrategy.TYPEALIAS_TYPE_REFERENCE) { parameter("typealiasedClassId") } + + val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning(PositioningStrategy.DECLARATION_NAME_ONLY) { + parameter("expect") + parameter("actual") + } } val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index fb34946b175..7e149aea159 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -628,6 +628,7 @@ object FirErrors { val NOT_A_MULTIPLATFORM_COMPILATION by error0() val EXPECT_ACTUAL_OPT_IN_ANNOTATION by error0(SourceElementPositioningStrategies.EXPECT_ACTUAL_MODIFIER) val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error1(SourceElementPositioningStrategies.TYPEALIAS_TYPE_REFERENCE) + val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning2, FirBasedSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME_ONLY) // Destructuring declaration val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt index 8a6689fa677..f1f85bd076a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt @@ -20,17 +20,20 @@ import org.jetbrains.kotlin.fir.declarations.utils.isActual import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isExternal import org.jetbrains.kotlin.fir.declarations.utils.isTailRec +import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.scopes.collectAllFunctions import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals -import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.toSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker import org.jetbrains.kotlin.resolve.checkers.OptInNames import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.* @@ -176,7 +179,9 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { else -> {} } - val expectedSingleCandidate = symbol.getSingleExpectForActualOrNull() + // We want to report errors even if a candidate is incompatible, but it's single + val expectedSingleCandidate = compatibilityToMembersMap[Compatible]?.singleOrNull() + ?: symbol.getSingleExpectForActualOrNull() if (expectedSingleCandidate != null) { checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias( expectedSingleCandidate, @@ -185,6 +190,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { reporter, ) checkOptInAnnotation(declaration, expectedSingleCandidate, context, reporter) + checkAnnotationsMatch(expectedSingleCandidate, symbol, context, reporter) } } @@ -243,6 +249,23 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { ) } + private fun checkAnnotationsMatch( + expectSymbol: FirBasedSymbol<*>, + actualSymbol: FirBasedSymbol<*>, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val matchingContext = context.session.expectActualMatchingContextFactory.create(context.session, context.scopeSession) + val incompatibility = + AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectSymbol, actualSymbol, matchingContext) ?: return + reporter.reportOn( + actualSymbol.source, FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, + incompatibility.expectSymbol as FirBasedSymbol<*>, + incompatibility.actualSymbol as FirBasedSymbol<*>, + context + ) + } + fun Map, *>.allStrongIncompatibilities(): Boolean { return keys.all { it is Incompatible && it.kind == IncompatibilityKind.STRONG } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt index f02ec8834bf..aaaa864da29 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt @@ -178,4 +178,14 @@ object FirDiagnosticRenderers { } val FUNCTIONAL_TYPE_KINDS = KtDiagnosticRenderers.COLLECTION(FUNCTIONAL_TYPE_KIND) + + @OptIn(SymbolInternals::class) + val SYMBOL_WITH_ANNOTATIONS = Renderer { s: FirBasedSymbol<*> -> + FirRenderer( + typeRenderer = ConeTypeRenderer(), + idRenderer = ConeIdShortRenderer(), + classMemberRenderer = null, + bodyRenderer = null, + ).renderElementAsString(s.fir, trim = true) + } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 6c195478f51..dfb39f6ada8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -51,6 +51,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL_WARNING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING @@ -1854,6 +1855,13 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { "`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.", TO_STRING ) + map.put( + ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, + "All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" + + "Expected: {0}\n" + + "Actual: {1}", + FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS, FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS + ) // Destructuring declaration map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration") 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 fc9d6a72377..1c69a322ebf 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 @@ -11,12 +11,13 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext import org.jetbrains.kotlin.fir.FirExpectActualMatchingContextFactory import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase -import org.jetbrains.kotlin.fir.declarations.collectEnumEntries -import org.jetbrains.kotlin.fir.declarations.isAnnotationConstructor +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.FirConstExpression +import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.dfa.coneType import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.mpp.* 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.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.Variance @@ -311,6 +313,48 @@ class FirExpectActualMatchingContextImpl private constructor( override val CallableSymbolMarker.hasStableParameterNames: Boolean get() = asSymbol().rawStatus.hasStableParameterNames + override val DeclarationSymbolMarker.annotations: List + get() = asSymbol().resolvedAnnotationsWithArguments.map(::AnnotationCallInfoImpl) + + override fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean { + fun AnnotationCallInfo.getFirAnnotation(): FirAnnotation { + return (this as AnnotationCallInfoImpl).annotation + } + return areFirAnnotationsEqual(annotation1.getFirAnnotation(), annotation2.getFirAnnotation()) + } + + private fun areFirAnnotationsEqual(annotation1: FirAnnotation, annotation2: FirAnnotation): Boolean { + if (!areCompatibleExpectActualTypes(annotation1.typeRef.coneType, annotation2.typeRef.coneType)) { + return false + } + val args1 = annotation1.argumentMapping.mapping + val args2 = annotation2.argumentMapping.mapping + if (args1.size != args2.size) { + return false + } + return args1.all { (key, value1) -> + val value2 = args2[key] + value2 != null && areAnnotationArgumentsEqual(value1, value2) + } + } + + private fun areAnnotationArgumentsEqual(expression1: FirExpression, expression2: FirExpression): Boolean { + // In K2 const expression calculated in backend. + // Because of that, we have "honest" checker at backend IR stage + // and "only simplest case" checker in frontend, so that we have at least some reporting in the IDE. + return when { + expression1 is FirConstExpression<*> && expression2 is FirConstExpression<*> -> { + expression1.value == expression2.value + } + else -> true + } + } + + private inner class AnnotationCallInfoImpl(val annotation: FirAnnotation) : AnnotationCallInfo { + override val classId: ClassId? + get() = annotation.toAnnotationClassId(actualSession) + } + object Factory : FirExpectActualMatchingContextFactory { override fun create(session: FirSession, scopeSession: ScopeSession): FirExpectActualMatchingContextImpl = FirExpectActualMatchingContextImpl(session, scopeSession) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 77bedf06920..211adac8175 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -840,6 +840,8 @@ public interface Errors { DiagnosticFactory0 EXPECT_ACTUAL_OPT_IN_ANNOTATION = DiagnosticFactory0.create(ERROR, EXPECT_ACTUAL_MODIFIER); DiagnosticFactory1 ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION = DiagnosticFactory1.create(ERROR, TYPEALIAS_TYPE_REFERENCE); + DiagnosticFactory2 ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT + = DiagnosticFactory2.create(WARNING, DECLARATION_NAME_ONLY); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 3415c94628c..499f5000419 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -396,6 +396,11 @@ public class DefaultErrorMessages { MAP.put(ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION, "`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.", TO_STRING); + MAP.put(ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, + "All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" + + " Expected: {0}\n" + + " Actual: {1}", + DESCRIPTOR_WITH_ANNOTATIONS, DESCRIPTOR_WITH_ANNOTATIONS); MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties"); MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index dfd885dca97..4eaa097945b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -32,8 +32,10 @@ import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.DEBUG_TEXT +import org.jetbrains.kotlin.renderer.DescriptorRendererModifier import org.jetbrains.kotlin.renderer.PropertyAccessorRenderingPolicy import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.calls.inference.* @@ -708,6 +710,14 @@ object Renderers { val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer() @JvmField val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer() + + @JvmField + val DESCRIPTOR_WITH_ANNOTATIONS = DescriptorRenderer.withOptions { + annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY + modifiers = modifiers.plus(DescriptorRendererModifier.ANNOTATIONS) + withDefinedIn = true + }.asRenderer() + @JvmField val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions { withoutTypeParameters = false 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 9936d75aa0d..5fce14f8fd0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor import org.jetbrains.kotlin.resolve.descriptorUtil.isPrimaryConstructorOfInlineClass @@ -338,9 +339,11 @@ class ExpectedActualDeclarationChecker( checkOptInAnnotation(reportOn, descriptor, expected, trace) } } - val expectSingleCandidate = compatibility.values.singleOrNull()?.singleOrNull() + // We want to report errors even if a candidate is incompatible, but it's single + val expectSingleCandidate = (compatibility[Compatible] ?: compatibility.values.singleOrNull())?.singleOrNull() if (expectSingleCandidate != null) { checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias(expectSingleCandidate, reportOn, trace) + checkAnnotationsMatch(expectSingleCandidate, descriptor, reportOn, trace) } } @@ -443,6 +446,24 @@ class ExpectedActualDeclarationChecker( } } + private fun checkAnnotationsMatch( + expectDescriptor: MemberDescriptor, + actualDescriptor: MemberDescriptor, + reportOn: KtNamedDeclaration, + trace: BindingTrace + ) { + val context = ClassicExpectActualMatchingContext(actualDescriptor.module) + val incompatibility = + AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectDescriptor, actualDescriptor, context) ?: return + trace.report( + Errors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT.on( + reportOn, + incompatibility.expectSymbol as DeclarationDescriptor, + incompatibility.actualSymbol as DeclarationDescriptor + ) + ) + } + companion object { fun Map, Collection>.allStrongIncompatibilities(): Boolean = this.keys.all { it is Incompatible && it.kind == IncompatibilityKind.STRONG } 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 bce274388b4..0583fc26ddc 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl @@ -25,7 +26,10 @@ import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.Variance -import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.types.model.AnnotationMarker +import org.jetbrains.kotlin.types.model.KotlinTypeMarker +import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker +import org.jetbrains.kotlin.types.model.TypeSystemContext import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction import org.jetbrains.kotlin.utils.addToStdlib.castAll import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled @@ -75,6 +79,7 @@ internal abstract class IrExpectActualMatchingContext( private fun TypeParameterSymbolMarker.asIr(): IrTypeParameter = (this as IrTypeParameterSymbol).owner private fun RegularClassSymbolMarker.asIr(): IrClass = (this as IrClassSymbol).owner private fun TypeAliasSymbolMarker.asIr(): IrTypeAlias = (this as IrTypeAliasSymbol).owner + private fun AnnotationMarker.asIr(): IrConstructorCall = this as IrConstructorCall private inline fun DeclarationSymbolMarker.safeAsIr(): T? = (this as IrSymbol).owner as? T @@ -440,4 +445,13 @@ internal abstract class IrExpectActualMatchingContext( abstract fun onMatchedClasses(expectClassSymbol: IrClassSymbol, actualClassSymbol: IrClassSymbol) abstract fun onMatchedCallables(expectSymbol: IrSymbol, actualSymbol: IrSymbol) + + override val DeclarationSymbolMarker.annotations: List + // TODO(Roman.Efremov): implement in subsequent commits + get() = emptyList() + + override fun areAnnotationArgumentsEqual(annotation1: ExpectActualMatchingContext.AnnotationCallInfo, annotation2: ExpectActualMatchingContext.AnnotationCallInfo): Boolean { + // TODO(Roman.Efremov): implement in subsequent commits + return true + } } 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 new file mode 100644 index 00000000000..0940c377a0e --- /dev/null +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2023 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. + */ + +package org.jetbrains.kotlin.resolve.calls.mpp + +import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker +import org.jetbrains.kotlin.mpp.TypeAliasSymbolMarker + +object AbstractExpectActualAnnotationMatchChecker { + class Incompatibility(val expectSymbol: DeclarationSymbolMarker, val actualSymbol: DeclarationSymbolMarker) + + fun areAnnotationsCompatible( + expectSymbol: DeclarationSymbolMarker, + actualSymbol: DeclarationSymbolMarker, + context: ExpectActualMatchingContext<*>, + ): Incompatibility? = with(context) { areAnnotationsCompatible(expectSymbol, actualSymbol) } + + context (ExpectActualMatchingContext<*>) + private fun areAnnotationsCompatible( + expectSymbol: DeclarationSymbolMarker, + actualSymbol: DeclarationSymbolMarker, + ): Incompatibility? { + if (actualSymbol is TypeAliasSymbolMarker) { + val expanded = actualSymbol.expandToRegularClass() ?: return null + return areAnnotationsCompatible(expectSymbol, expanded) + } + + val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId } + + for (expectAnnotation in expectSymbol.annotations) { + val actualAnnotationsWithSameClassId = actualAnnotationsByName[expectAnnotation.classId] ?: emptyList() + if (actualAnnotationsWithSameClassId.none { areAnnotationArgumentsEqual(expectAnnotation, it) }) { + return Incompatibility(expectSymbol, actualSymbol) + } + } + return null + } +} \ No newline at end of file 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 3d53f1f3696..138668e2e66 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 @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.mpp.* import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.types.Variance @@ -157,4 +158,12 @@ interface ExpectActualMatchingContext : TypeSystemC expectSymbol: DeclarationSymbolMarker, actualSymbolsByIncompatibility: Map, List> ) {} + + val DeclarationSymbolMarker.annotations: List + + fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean + + interface AnnotationCallInfo { + val classId: ClassId? + } } 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 8a25e913765..3d9f14bc1bc 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.resolve.multiplatform import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.mpp.* import org.jetbrains.kotlin.name.CallableId @@ -14,9 +15,8 @@ import org.jetbrains.kotlin.name.Name 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.descriptorUtil.classId -import org.jetbrains.kotlin.resolve.descriptorUtil.getKotlinTypeRefiner -import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled +import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo +import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered @@ -35,6 +35,7 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) : override val shouldCheckReturnTypesOfCallables: Boolean get() = true + private fun DeclarationSymbolMarker.asDescriptor(): DeclarationDescriptor = this as DeclarationDescriptor private fun CallableSymbolMarker.asDescriptor(): CallableDescriptor = this as CallableDescriptor private fun FunctionSymbolMarker.asDescriptor(): FunctionDescriptor = this as FunctionDescriptor private fun PropertySymbolMarker.asDescriptor(): PropertyDescriptor = this as PropertyDescriptor @@ -328,4 +329,21 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) : override val CallableSymbolMarker.hasStableParameterNames: Boolean get() = asDescriptor().hasStableParameterNames() + + override val DeclarationSymbolMarker.annotations: List + get() = asDescriptor().annotations.map(::AnnotationCallInfoImpl) + + + override fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean { + fun AnnotationCallInfo.getDescriptor(): AnnotationDescriptor = (this as AnnotationCallInfoImpl).annotationDescriptor + + return areExpressionConstValuesEqual(annotation1.getDescriptor(), annotation2.getDescriptor()) + } + + private class AnnotationCallInfoImpl( + val annotationDescriptor: AnnotationDescriptor, + ) : AnnotationCallInfo { + override val classId: ClassId? + get() = annotationDescriptor.annotationClass?.classId + } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/constExpressionValuesEqualityChecker.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/constExpressionValuesEqualityChecker.kt new file mode 100644 index 00000000000..34b3d46bfb5 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/constExpressionValuesEqualityChecker.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2023 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. + */ + +package org.jetbrains.kotlin.resolve.multiplatform + +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext +import org.jetbrains.kotlin.resolve.constants.ConstantValue + +internal fun ExpectActualMatchingContext<*>.areExpressionConstValuesEqual(a: Any?, b: Any?): Boolean { + return when { + a is AnnotationDescriptor && b is AnnotationDescriptor -> { + val aArgs = a.allValueArguments + val bArgs = b.allValueArguments + a.fqName == b.fqName && + aArgs.size == bArgs.size && + areCompatibleExpectActualTypes(a.type, b.type) && + aArgs.keys.all { k -> areExpressionConstValuesEqual(aArgs[k], bArgs[k]) } + } + a is ConstantValue<*> && b is ConstantValue<*> -> { + areExpressionConstValuesEqual(a.value, b.value) + } + a is Collection<*> && b is Collection<*> -> { + a.size == b.size && a.zip(b).all { (f, s) -> areExpressionConstValuesEqual(f, s) } + } + a is Array<*> && b is Array<*> -> { + a.size == b.size && a.zip(b).all { (f, s) -> areExpressionConstValuesEqual(f, s) } + } + else -> a == b + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.fir.kt new file mode 100644 index 00000000000..4b9f7e7a1e4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.fir.kt @@ -0,0 +1,138 @@ +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +package test + +import kotlin.reflect.KClass + +annotation class ClassArgAnn(val clazz: KClass<*>) + +class ClassForReference { + class ClassForReference +} + +@ClassArgAnn(ClassForReference::class) +expect fun getClassExpression() + +@ClassArgAnn(ClassForReference.ClassForReference::class) +expect fun differentClassesWithSameName() + +annotation class StringArgAnn(val s: String) + +@StringArgAnn("1.9") +expect fun stringConstant() + +@StringArgAnn("1" + ".9") +expect fun stringConcatentation() + +object Constants { + const val STR = "1" +} + +@StringArgAnn(Constants.STR) +expect fun constantFromInsideObject() + +@StringArgAnn(Constants.STR + ".9") +expect fun stringConcatentationWithProperty() + +enum class MyEnum { FOO, BAR } + +annotation class EnumArgAnn(val e: MyEnum) + +@EnumArgAnn(MyEnum.FOO) +expect fun enumArg() + +annotation class VarargAnn(vararg val strings: String) + +@VarargAnn("foo", "bar") +expect fun varargInAnnotation() + +@VarargAnn(*["foo", "bar"]) +expect fun varargInAnnotationWithArraySpread() + +annotation class ArrayArgAnn(val strings: Array) + +@ArrayArgAnn(["foo", "bar"]) +expect fun arrayInAnnotation() + +@ArrayArgAnn(["foo", "bar"]) +expect fun arrayInAnnotationNotMatch() + +annotation class NestedAnnArg(val text: String, vararg val children: NestedAnnArg) + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("2.2") + ) +) +expect fun complexNestedAnnotations() + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("2.2") + ) +) +expect fun complexNestedAnnotationsNotMatch() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +package test + +@ClassArgAnn(ClassForReference::class) +actual fun getClassExpression() {} + +@ClassArgAnn(ClassForReference::class) +actual fun differentClassesWithSameName() {} + +@StringArgAnn("1.9") +actual fun stringConstant() {} + +@StringArgAnn("1.9") +actual fun stringConcatentation() {} + +@StringArgAnn("1") +actual fun constantFromInsideObject() {} + +@StringArgAnn("1.9") +actual fun stringConcatentationWithProperty() {} + +@EnumArgAnn(MyEnum.FOO) +actual fun enumArg() {} + +@VarargAnn("foo", "bar") +actual fun varargInAnnotation() {} + +@VarargAnn("foo", "bar") +actual fun varargInAnnotationWithArraySpread() {} + +@ArrayArgAnn(arrayOf("foo", "bar")) +actual fun arrayInAnnotation() {} + +@ArrayArgAnn(["foo"]) +actual fun arrayInAnnotationNotMatch() {} + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("2.2") + ) +) +actual fun complexNestedAnnotations() {} + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("DIFFERENT") + ) +) +actual fun complexNestedAnnotationsNotMatch() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt new file mode 100644 index 00000000000..70f130ca5c3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt @@ -0,0 +1,138 @@ +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +package test + +import kotlin.reflect.KClass + +annotation class ClassArgAnn(val clazz: KClass<*>) + +class ClassForReference { + class ClassForReference +} + +@ClassArgAnn(ClassForReference::class) +expect fun getClassExpression() + +@ClassArgAnn(ClassForReference.ClassForReference::class) +expect fun differentClassesWithSameName() + +annotation class StringArgAnn(val s: String) + +@StringArgAnn("1.9") +expect fun stringConstant() + +@StringArgAnn("1" + ".9") +expect fun stringConcatentation() + +object Constants { + const val STR = "1" +} + +@StringArgAnn(Constants.STR) +expect fun constantFromInsideObject() + +@StringArgAnn(Constants.STR + ".9") +expect fun stringConcatentationWithProperty() + +enum class MyEnum { FOO, BAR } + +annotation class EnumArgAnn(val e: MyEnum) + +@EnumArgAnn(MyEnum.FOO) +expect fun enumArg() + +annotation class VarargAnn(vararg val strings: String) + +@VarargAnn("foo", "bar") +expect fun varargInAnnotation() + +@VarargAnn(*["foo", "bar"]) +expect fun varargInAnnotationWithArraySpread() + +annotation class ArrayArgAnn(val strings: Array) + +@ArrayArgAnn(["foo", "bar"]) +expect fun arrayInAnnotation() + +@ArrayArgAnn(["foo", "bar"]) +expect fun arrayInAnnotationNotMatch() + +annotation class NestedAnnArg(val text: String, vararg val children: NestedAnnArg) + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("2.2") + ) +) +expect fun complexNestedAnnotations() + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("2.2") + ) +) +expect fun complexNestedAnnotationsNotMatch() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +package test + +@ClassArgAnn(ClassForReference::class) +actual fun getClassExpression() {} + +@ClassArgAnn(ClassForReference::class) +actual fun differentClassesWithSameName() {} + +@StringArgAnn("1.9") +actual fun stringConstant() {} + +@StringArgAnn("1.9") +actual fun stringConcatentation() {} + +@StringArgAnn("1") +actual fun constantFromInsideObject() {} + +@StringArgAnn("1.9") +actual fun stringConcatentationWithProperty() {} + +@EnumArgAnn(MyEnum.FOO) +actual fun enumArg() {} + +@VarargAnn("foo", "bar") +actual fun varargInAnnotation() {} + +@VarargAnn("foo", "bar") +actual fun varargInAnnotationWithArraySpread() {} + +@ArrayArgAnn(arrayOf("foo", "bar")) +actual fun arrayInAnnotation() {} + +@ArrayArgAnn(["foo"]) +actual fun arrayInAnnotationNotMatch() {} + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("2.2") + ) +) +actual fun complexNestedAnnotations() {} + +@NestedAnnArg( + text = "root", + NestedAnnArg("1"), + NestedAnnArg("2", + NestedAnnArg("2.1"), + NestedAnnArg("DIFFERENT") + ) +) +actual fun complexNestedAnnotationsNotMatch() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt new file mode 100644 index 00000000000..ab0d99f2c73 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt @@ -0,0 +1,12 @@ +// FIR_IDENTICAL +// MODULE: m1-common +// FILE: common.kt +annotation class Ann(val p: String = "") +@Ann("") +expect fun explicitDefaultArgument() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +// No special handling for this case +@Ann +actual fun explicitDefaultArgument() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.fir.kt new file mode 100644 index 00000000000..9562eea8150 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.fir.kt @@ -0,0 +1,101 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +class A +class B +private object FakeA { + class A +} + +@Ann +expect fun sameTypeParam() + +@Ann +expect fun differentTypeParam() + +@Ann +expect fun differentWithSameName() + +@Ann +expect fun nonNullvsNull() + +@Ann> +expect fun differentVariance() + +@Ann> +expect fun varianceVsNoVariance() + +@Ann> +expect fun sameVariance() + +@Ann> +expect fun startProjection() + +annotation class ComplexNested( + vararg val anns: ComplexNested<*>, +) + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +expect fun complexSame() + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +expect fun complexDiffer() + +annotation class NestedWithSameTypeArgument( + vararg val anns: NestedWithSameTypeArgument +) + +@NestedWithSameTypeArgument( + NestedWithSameTypeArgument() +) +expect fun explicitVsInfered() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +@Ann +actual fun sameTypeParam() {} + +@Ann +actual fun differentTypeParam() {} + +@Ann +actual fun differentWithSameName() {} + +@Ann +actual fun nonNullvsNull() {} + +@Ann> +actual fun differentVariance() {} + +@Ann> +actual fun varianceVsNoVariance() {} + +@Ann> +actual fun sameVariance() {} + +@Ann> +actual fun startProjection() {} + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +actual fun complexSame() {} + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +actual fun complexDiffer() {} + +@NestedWithSameTypeArgument( + NestedWithSameTypeArgument() +) +actual fun explicitVsInfered() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt new file mode 100644 index 00000000000..af55812ade3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt @@ -0,0 +1,101 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +class A +class B +private object FakeA { + class A +} + +@Ann +expect fun sameTypeParam() + +@Ann +expect fun differentTypeParam() + +@Ann +expect fun differentWithSameName() + +@Ann +expect fun nonNullvsNull() + +@Ann> +expect fun differentVariance() + +@Ann> +expect fun varianceVsNoVariance() + +@Ann> +expect fun sameVariance() + +@Ann> +expect fun startProjection() + +annotation class ComplexNested( + vararg val anns: ComplexNested<*>, +) + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +expect fun complexSame() + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +expect fun complexDiffer() + +annotation class NestedWithSameTypeArgument( + vararg val anns: NestedWithSameTypeArgument +) + +@NestedWithSameTypeArgument( + NestedWithSameTypeArgument() +) +expect fun explicitVsInfered() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +@Ann +actual fun sameTypeParam() {} + +@Ann +actual fun differentTypeParam() {} + +@Ann +actual fun differentWithSameName() {} + +@Ann +actual fun nonNullvsNull() {} + +@Ann> +actual fun differentVariance() {} + +@Ann> +actual fun varianceVsNoVariance() {} + +@Ann> +actual fun sameVariance() {} + +@Ann> +actual fun startProjection() {} + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +actual fun complexSame() {} + +@ComplexNested( + ComplexNested(), + ComplexNested(), +) +actual fun complexDiffer() {} + +@NestedWithSameTypeArgument( + NestedWithSameTypeArgument() +) +actual fun explicitVsInfered() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt new file mode 100644 index 00000000000..b556a5b9340 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt @@ -0,0 +1,42 @@ +// FIR_IDENTICAL +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +@Ann +expect class AnnotationMatching + +@Ann +expect class AnnotationOnExpectOnly + +expect class AnnotationOnActualOnly + +expect class AnnotationInside { + @Ann + fun matches() + + @Ann + fun onlyOnExpect() + + fun onlyOnActual() +} + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +@Ann +actual class AnnotationMatching + +actual class AnnotationOnExpectOnly + +@Ann +actual class AnnotationOnActualOnly + +actual class AnnotationInside { + @Ann + actual fun matches() {} + + actual fun onlyOnExpect() {} + + @Ann + actual fun onlyOnActual() {} +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt new file mode 100644 index 00000000000..a3b3799c143 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt @@ -0,0 +1,19 @@ +// -- Module: -- + +// -- Module: -- +/jvm.kt:24:14: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. + Expected: @Ann public final expect class OnClass defined in root package in file common.kt + Actual: public final actual class OnClass defined in root package in file jvm.kt +actual class OnClass + ^ +/jvm.kt:27:16: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. + Expected: @Ann public final expect fun onMember(): Unit defined in OnMember + Actual: public final actual fun onMember(): Unit defined in OnMember + actual fun onMember() {} + ^ +/jvm.kt:34:18: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. + Expected: @Ann public final expect class ViaTypealias defined in root package in file common.kt + Actual: public final class ViaTypealiasImpl defined in root package in file jvm.kt +actual typealias ViaTypealias = ViaTypealiasImpl + ^ + diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt new file mode 100644 index 00000000000..8fac224fe63 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt @@ -0,0 +1,11 @@ +/jvm.kt:(83,90): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. +Expected: @Ann() public final expect class OnClass : Any +Actual: public final actual class OnClass : Any + +/jvm.kt:(131,139): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. +Expected: @Ann() public final expect fun onMember(): Unit +Actual: public final actual fun onMember(): Unit + +/jvm.kt:(210,222): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. +Expected: @Ann() public final expect class ViaTypealias : Any +Actual: public final class ViaTypealiasImpl : Any diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt new file mode 100644 index 00000000000..e90fe80bea3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt @@ -0,0 +1,34 @@ +// FIR_IDENTICAL +// RENDER_DIAGNOSTICS_FULL_TEXT +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +@Ann +expect class OnClass + +expect class OnMember { + @Ann + fun onMember() +} + +@Ann +expect class ViaTypealias { + @Ann + fun foo() +} + + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual class OnClass + +actual class OnMember { + actual fun onMember() {} +} + +class ViaTypealiasImpl { + fun foo() {} +} + +actual typealias ViaTypealias = ViaTypealiasImpl diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt new file mode 100644 index 00000000000..c5d1bc10d1b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt @@ -0,0 +1,19 @@ +// FIR_IDENTICAL +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +expect class CompatibleOverrides { + fun foo() + + @Ann + fun foo(withArg: Any) +} + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual class CompatibleOverrides { + actual fun foo() {} + + actual fun foo(withArg: Any) {} +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.fir.kt new file mode 100644 index 00000000000..06ee04e8cd6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.fir.kt @@ -0,0 +1,31 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann1 +annotation class Ann2 + +@Ann1 +@Ann2 +expect class AnnotationOrder + +annotation class Ann3(vararg val numbers: Int) + +@Ann3(1, 2) +expect class ValuesOrderInsideAnnotationArgument + +annotation class Ann4(val arg1: String, val arg2: String) + +@Ann4(arg1 = "1", arg2 = "2") +expect fun differentArgumentsOrder() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt + +@Ann2 +@Ann1 +actual class AnnotationOrder + +@Ann3(2, 1) +actual class ValuesOrderInsideAnnotationArgument + +@Ann4(arg2 = "2", arg1 = "1") +actual fun differentArgumentsOrder() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt new file mode 100644 index 00000000000..c6d4a753f71 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt @@ -0,0 +1,31 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann1 +annotation class Ann2 + +@Ann1 +@Ann2 +expect class AnnotationOrder + +annotation class Ann3(vararg val numbers: Int) + +@Ann3(1, 2) +expect class ValuesOrderInsideAnnotationArgument + +annotation class Ann4(val arg1: String, val arg2: String) + +@Ann4(arg1 = "1", arg2 = "2") +expect fun differentArgumentsOrder() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt + +@Ann2 +@Ann1 +actual class AnnotationOrder + +@Ann3(2, 1) +actual class ValuesOrderInsideAnnotationArgument + +@Ann4(arg2 = "2", arg1 = "1") +actual fun differentArgumentsOrder() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.fir.kt new file mode 100644 index 00000000000..26d4b70e4b9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.fir.kt @@ -0,0 +1,11 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann(val p: Double) + +@Ann(0.3) +expect fun floatNumbersComparison() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +@Ann(0.1 + 0.1 + 0.1) +actual fun floatNumbersComparison() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt new file mode 100644 index 00000000000..37a28e3867f --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt @@ -0,0 +1,11 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann(val p: Double) + +@Ann(0.3) +expect fun floatNumbersComparison() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +@Ann(0.1 + 0.1 + 0.1) +actual fun floatNumbersComparison() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt new file mode 100644 index 00000000000..53601d86985 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt @@ -0,0 +1,35 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +import kotlin.reflect.KClass + +annotation class Ann(val clazz: KClass<*>) + +@Ann(LinkToExpectInnerClass.Inner::class) +expect class LinkToExpectInnerClass { + object Inner +} + +expect class WillBeTypealiased + +@Ann(WillBeTypealiased::class) +expect fun linkToExpectClassWhichWillBeTypealiased() + +@Ann(WillBeTypealiased::class) +expect fun linkToExpectClassWhichWillBeTypealiased2() + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +@Ann(LinkToExpectInnerClass.Inner::class) +actual class LinkToExpectInnerClass { + actual object Inner +} + +actual typealias WillBeTypealiased = Any + +@Ann(WillBeTypealiased::class) +actual fun linkToExpectClassWhichWillBeTypealiased() {} + +@Ann(Any::class) +actual fun linkToExpectClassWhichWillBeTypealiased2() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt new file mode 100644 index 00000000000..b43af906a5f --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt @@ -0,0 +1,29 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +@Retention(AnnotationRetention.RUNTIME) +expect annotation class JavaTypealiasAnnotationAnalogue + +@Retention(AnnotationRetention.RUNTIME) +expect annotation class JavaTypealiasKotlinAnnotation + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual typealias JavaTypealiasAnnotationAnalogue = JavaTypealiasAnnotationAnalogueImpl + +actual typealias JavaTypealiasKotlinAnnotation = JavaTypealiasKotlinAnnotationImpl + +// FILE: jvmJavaImpls.java +import kotlin.annotation.AnnotationRetention; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface JavaTypealiasAnnotationAnalogueImpl { +} + +@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) +public @interface JavaTypealiasKotlinAnnotationImpl { +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt new file mode 100644 index 00000000000..2d83224b0f2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt @@ -0,0 +1,23 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +@Target(AnnotationTarget.TYPEALIAS, AnnotationTarget.CLASS) +annotation class Ann + +@Ann +expect class KtTypealiasNotMatch + +@Ann +expect class AnnotationsNotConsideredOnTypealias + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +class KtTypealiasNotMatchImpl + +actual typealias KtTypealiasNotMatch = KtTypealiasNotMatchImpl + +class AnnotationsNotConsideredOnTypealiasImpl + +@Ann +actual typealias AnnotationsNotConsideredOnTypealias = AnnotationsNotConsideredOnTypealiasImpl diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.fir.kt new file mode 100644 index 00000000000..7b383c136e2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.fir.kt @@ -0,0 +1,14 @@ +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +@Retention(AnnotationRetention.SOURCE) +expect annotation class MyDeprecatedNotMatch + +@Retention(AnnotationRetention.RUNTIME) +expect annotation class MyDeprecatedMatch + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual typealias MyDeprecatedNotMatch = java.lang.Deprecated + +actual typealias MyDeprecatedMatch = java.lang.Deprecated diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt new file mode 100644 index 00000000000..1fe664de211 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt @@ -0,0 +1,14 @@ +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +@Retention(AnnotationRetention.SOURCE) +expect annotation class MyDeprecatedNotMatch + +@Retention(AnnotationRetention.RUNTIME) +expect annotation class MyDeprecatedMatch + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual typealias MyDeprecatedNotMatch = java.lang.Deprecated + +actual typealias MyDeprecatedMatch = java.lang.Deprecated diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.fir.kt new file mode 100644 index 00000000000..fc432fcdd88 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.fir.kt @@ -0,0 +1,32 @@ +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.ANNOTATION_CLASS, + AnnotationTarget.CONSTRUCTOR, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.PROPERTY_GETTER, + // removed target TYPEALIAS +) +expect annotation class MyDeprecatedNotMatch + +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.ANNOTATION_CLASS, + AnnotationTarget.CONSTRUCTOR, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.TYPEALIAS +) +expect annotation class MyDeprecatedMatch + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual typealias MyDeprecatedNotMatch = kotlin.Deprecated + +actual typealias MyDeprecatedMatch = kotlin.Deprecated diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt new file mode 100644 index 00000000000..81e80010d4b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt @@ -0,0 +1,32 @@ +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.ANNOTATION_CLASS, + AnnotationTarget.CONSTRUCTOR, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.PROPERTY_GETTER, + // removed target TYPEALIAS +) +expect annotation class MyDeprecatedNotMatch + +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.ANNOTATION_CLASS, + AnnotationTarget.CONSTRUCTOR, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.TYPEALIAS +) +expect annotation class MyDeprecatedMatch + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual typealias MyDeprecatedNotMatch = kotlin.Deprecated + +actual typealias MyDeprecatedMatch = kotlin.Deprecated diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.fir.kt new file mode 100644 index 00000000000..9adfe1abe9d --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.fir.kt @@ -0,0 +1,19 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +@Ann +expect inline fun hasWeakIncompatibility() + +@Ann +expect fun hasStrongIncompatibility(arg: Int) + +expect fun hasStrongIncompatibility(arg: Double) + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual fun hasWeakIncompatibility() {} + +actual fun hasStrongIncompatibility(arg: Any?) {} + +actual fun hasStrongIncompatibility(arg: Double) {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt new file mode 100644 index 00000000000..bd74a43a581 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt @@ -0,0 +1,19 @@ +// MODULE: m1-common +// FILE: common.kt +annotation class Ann + +@Ann +expect inline fun hasWeakIncompatibility() + +@Ann +expect fun hasStrongIncompatibility(arg: Int) + +expect fun hasStrongIncompatibility(arg: Double) + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual fun hasWeakIncompatibility() {} + +actual fun hasStrongIncompatibility(arg: Any?) {} + +actual fun hasStrongIncompatibility(arg: Double) {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.fir.kt index 8bcff214851..134586ad3db 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.fir.kt @@ -1,12 +1,13 @@ // WITH_STDLIB // MODULE: m1-common // FILE: common.kt +@file:OptIn(ExperimentalMultiplatform::class) + expect annotation class ActualOnly @RequiresOptIn expect annotation class Both -@OptIn(ExperimentalMultiplatform::class) @RequiresOptIn @OptionalExpectation expect annotation class MyOptIn diff --git a/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.kt b/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.kt index a8a824545f8..9e1be8f579a 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/expectOptInAnnotation.kt @@ -1,12 +1,13 @@ // WITH_STDLIB // MODULE: m1-common // FILE: common.kt +@file:OptIn(ExperimentalMultiplatform::class) + expect annotation class ActualOnly @RequiresOptIn expect annotation class Both -@OptIn(ExperimentalMultiplatform::class) @RequiresOptIn @OptionalExpectation expect annotation class MyOptIn diff --git a/compiler/testData/multiplatform/optionalExpectation/common.kt b/compiler/testData/multiplatform/optionalExpectation/common.kt index 11a8f4c2af8..862ef1b5bbe 100644 --- a/compiler/testData/multiplatform/optionalExpectation/common.kt +++ b/compiler/testData/multiplatform/optionalExpectation/common.kt @@ -4,7 +4,7 @@ @OptionalExpectation expect annotation class A() -expect class C { +class C { @A - fun f() + fun f() {} } diff --git a/compiler/testData/multiplatform/optionalExpectation/js.kt b/compiler/testData/multiplatform/optionalExpectation/js.kt index 34c8433a32b..e69de29bb2d 100644 --- a/compiler/testData/multiplatform/optionalExpectation/js.kt +++ b/compiler/testData/multiplatform/optionalExpectation/js.kt @@ -1,3 +0,0 @@ -actual class C { - actual fun f() {} -} diff --git a/compiler/testData/multiplatform/optionalExpectation/jvm.kt b/compiler/testData/multiplatform/optionalExpectation/jvm.kt index 0fe40c3c1e7..f0c753245e0 100644 --- a/compiler/testData/multiplatform/optionalExpectation/jvm.kt +++ b/compiler/testData/multiplatform/optionalExpectation/jvm.kt @@ -1,6 +1 @@ actual annotation class A - -actual class C { - @A - actual fun f() {} -} 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 743391f1114..618beb5f082 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 @@ -22750,6 +22750,100 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching") + @TestDataPath("$PROJECT_ROOT") + public class AnnotationMatching { + @Test + public void testAllFilesPresentInAnnotationMatching() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); + } + + @Test + @TestMetadata("annotationArgumentsConstExpressions.kt") + public void testAnnotationArgumentsConstExpressions() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt"); + } + + @Test + @TestMetadata("annotationArgumentsDefaults.kt") + public void testAnnotationArgumentsDefaults() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt"); + } + + @Test + @TestMetadata("annotationTypeParameters.kt") + public void testAnnotationTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt"); + } + + @Test + @TestMetadata("basicOnDeclaration.kt") + public void testBasicOnDeclaration() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt"); + } + + @Test + @TestMetadata("checkDiagnosticFullText.kt") + public void testCheckDiagnosticFullText() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt"); + } + + @Test + @TestMetadata("compatibleOverrides.kt") + public void testCompatibleOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt"); + } + + @Test + @TestMetadata("differentOrder.kt") + public void testDifferentOrder() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt"); + } + + @Test + @TestMetadata("floatNumbersComparison.kt") + public void testFloatNumbersComparison() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt"); + } + + @Test + @TestMetadata("kclassArgWithExpectClass.kt") + public void testKclassArgWithExpectClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt"); + } + + @Test + @TestMetadata("kotlinAnaloguesForJavaAnnotations.kt") + public void testKotlinAnaloguesForJavaAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt"); + } + + @Test + @TestMetadata("typealias.kt") + public void testTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt"); + } + + @Test + @TestMetadata("typealiasToJavaLibrary.kt") + public void testTypealiasToJavaLibrary() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt"); + } + + @Test + @TestMetadata("typealiasToKtLibrary.kt") + public void testTypealiasToKtLibrary() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt"); + } + + @Test + @TestMetadata("withOtherIncomatibilities.kt") + public void testWithOtherIncomatibilities() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments") @TestDataPath("$PROJECT_ROOT")