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 5b5252a50f2..63c10a481df 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 @@ -286,6 +286,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); } + @Test + @TestMetadata("sourceRetentionAnnotationsWhenTypealias.kt") + public void testSourceRetentionAnnotationsWhenTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt"); + } + @Test @TestMetadata("typealias.kt") public void testTypealias() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index 23e3463b7f6..23cb7095875 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 @@ -286,6 +286,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); } + @Test + @TestMetadata("sourceRetentionAnnotationsWhenTypealias.kt") + public void testSourceRetentionAnnotationsWhenTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt"); + } + @Test @TestMetadata("typealias.kt") public void testTypealias() throws Exception { 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 1c69a322ebf..c01a56eda4f 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,13 +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.analysis.getRetention 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 @@ -353,8 +353,20 @@ class FirExpectActualMatchingContextImpl private constructor( private inner class AnnotationCallInfoImpl(val annotation: FirAnnotation) : AnnotationCallInfo { override val classId: ClassId? get() = annotation.toAnnotationClassId(actualSession) + + override val isRetentionSource: Boolean + get() = getAnnotationClass()?.getRetention(actualSession) == AnnotationRetention.SOURCE + + private fun getAnnotationClass(): FirRegularClassSymbol? = + annotation.annotationTypeRef.coneType.toRegularClassSymbol(actualSession) } + override val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean + get() { + val symbol = asSymbol() + return symbol.source != null || symbol.origin is FirDeclarationOrigin.Plugin + } + object Factory : FirExpectActualMatchingContextFactory { override fun create(session: FirSession, scopeSession: ScopeSession): FirExpectActualMatchingContextImpl = FirExpectActualMatchingContextImpl(session, scopeSession) diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/analysis/FirRetentionAnnotationHelpers.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/analysis/FirRetentionAnnotationHelpers.kt index 000f71bb2a0..10b5bdb5cfe 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/analysis/FirRetentionAnnotationHelpers.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/analysis/FirRetentionAnnotationHelpers.kt @@ -6,19 +6,22 @@ package org.jetbrains.kotlin.fir.analysis import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirDeclaration -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.findArgumentByName -import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.references.toResolvedEnumEntrySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.StandardClassIds fun FirRegularClass.getRetention(session: FirSession): AnnotationRetention { return getRetentionAnnotation(session)?.getRetention() ?: AnnotationRetention.RUNTIME } +fun FirRegularClassSymbol.getRetention(session: FirSession): AnnotationRetention { + return getRetentionAnnotation(session)?.getRetention() ?: AnnotationRetention.RUNTIME +} + fun FirAnnotation.getRetention(): AnnotationRetention? { val propertyAccess = findArgumentByName(StandardClassIds.Annotations.ParameterNames.retentionValue) as? FirQualifiedAccessExpression val callableId = propertyAccess?.calleeReference?.toResolvedEnumEntrySymbol()?.callableId ?: return null @@ -33,3 +36,11 @@ fun FirAnnotation.getRetention(): AnnotationRetention? { fun FirDeclaration.getRetentionAnnotation(session: FirSession): FirAnnotation? { return getAnnotationByClassId(StandardClassIds.Annotations.Retention, session) } + +private fun FirRegularClassSymbol.getRetentionAnnotation(session: FirSession): FirAnnotation? { + return getAnnotationByClassId(StandardClassIds.Annotations.Retention, session) +} + +private fun FirRegularClassSymbol.getAnnotationByClassId(classId: ClassId, session: FirSession): FirAnnotation? { + return resolvedAnnotationsWithArguments.firstOrNull { it.toAnnotationClassId(session) == classId } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt index f011321053d..e73e2f8720d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase +import org.jetbrains.kotlin.mpp.K1SyntheticClassifierSymbolMarker import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext @@ -50,7 +51,8 @@ class SyntheticClassOrObjectDescriptor( constructorVisibility: DescriptorVisibility, private val kind: ClassKind, private val isCompanionObject: Boolean -) : ClassDescriptorBase(c.storageManager, containingDeclaration, name, source, false), ClassDescriptorWithResolutionScopes { +) : ClassDescriptorBase(c.storageManager, containingDeclaration, name, source, false), ClassDescriptorWithResolutionScopes, + K1SyntheticClassifierSymbolMarker { val syntheticDeclaration: KtPureClassOrObject = SyntheticDeclaration(parentClassOrObject, name.asString()) private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability 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 356adf90ef6..056f71c03be 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 @@ -5,13 +5,14 @@ package org.jetbrains.kotlin.backend.common.actualizer +import org.jetbrains.kotlin.backend.common.sourceElement import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrConstructorCall -import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl @@ -464,5 +465,17 @@ internal abstract class IrExpectActualMatchingContext( private class AnnotationCallInfoImpl(val irElement: IrConstructorCall) : AnnotationCallInfo { override val classId: ClassId? 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 + } } + + override val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean + get() { + val ir = asIr() + return ir.sourceElement() != null || ir.origin is IrDeclarationOrigin.GeneratedByPlugin + } } 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 5ab2f03648e..470194268e1 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 @@ -28,12 +28,16 @@ object AbstractExpectActualAnnotationMatchChecker { return areAnnotationsCompatible(expectSymbol, expanded) } + val skipSourceAnnotations = !actualSymbol.hasSourceAnnotationsErased val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId } for (expectAnnotation in expectSymbol.annotations) { if (expectAnnotation.classId == StandardClassIds.Annotations.OptionalExpectation) { continue } + if (expectAnnotation.isRetentionSource && skipSourceAnnotations) { + continue + } val actualAnnotationsWithSameClassId = actualAnnotationsByName[expectAnnotation.classId] ?: emptyList() if (actualAnnotationsWithSameClassId.none { areAnnotationArgumentsEqual(expectAnnotation, it) }) { return Incompatibility(expectSymbol, actualSymbol) 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 138668e2e66..b719dab61e0 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,7 +11,6 @@ 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 @@ -163,7 +162,10 @@ interface ExpectActualMatchingContext : TypeSystemC fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean + val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean + interface AnnotationCallInfo { val classId: ClassId? + val isRetentionSource: 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 3d9f14bc1bc..c38e728e336 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ClassicExpectActualMatchingContext.kt @@ -22,7 +22,10 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.* -import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.types.model.KotlinTypeMarker +import org.jetbrains.kotlin.types.model.TypeConstructorMarker +import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker +import org.jetbrains.kotlin.types.model.TypeSystemContext import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction import org.jetbrains.kotlin.utils.addToStdlib.castAll @@ -345,5 +348,15 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) : ) : AnnotationCallInfo { override val classId: ClassId? get() = annotationDescriptor.annotationClass?.classId + + override val isRetentionSource: Boolean + get() = annotationDescriptor.isSourceAnnotation } + + override val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean + get() { + return DescriptorUtils.getContainingSourceFile(asDescriptor()) != SourceFile.NO_SOURCE_FILE || + this is K1SyntheticClassifierSymbolMarker || + this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED + } } diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.fir.kt new file mode 100644 index 00000000000..d55ccc08beb --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.fir.kt @@ -0,0 +1,25 @@ +// WITH_STDLIB +// DIAGNOSTICS: -ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION +// MODULE: m1-common +// FILE: common.kt +@Retention(AnnotationRetention.SOURCE) +annotation class Ann + +@Ann +expect class SourceAvailable { + @Ann + fun foo() +} + +@Ann +expect annotation class FromLib + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +class SourceAvailableImpl { + fun foo() {} +} + +actual typealias SourceAvailable = SourceAvailableImpl + +actual typealias FromLib = kotlin.SinceKotlin diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt new file mode 100644 index 00000000000..ae77f743657 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt @@ -0,0 +1,25 @@ +// WITH_STDLIB +// DIAGNOSTICS: -ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION +// MODULE: m1-common +// FILE: common.kt +@Retention(AnnotationRetention.SOURCE) +annotation class Ann + +@Ann +expect class SourceAvailable { + @Ann + fun foo() +} + +@Ann +expect annotation class FromLib + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +class SourceAvailableImpl { + fun foo() {} +} + +actual typealias SourceAvailable = SourceAvailableImpl + +actual typealias FromLib = kotlin.SinceKotlin 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 8dfc2b4e25b..ba26948435b 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 @@ -22831,6 +22831,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); } + @Test + @TestMetadata("sourceRetentionAnnotationsWhenTypealias.kt") + public void testSourceRetentionAnnotationsWhenTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt"); + } + @Test @TestMetadata("typealias.kt") public void testTypealias() throws Exception { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/mpp/DeclarationSymbolMarkers.kt b/core/compiler.common/src/org/jetbrains/kotlin/mpp/DeclarationSymbolMarkers.kt index 801e090af17..bac3b82b2fe 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/mpp/DeclarationSymbolMarkers.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/mpp/DeclarationSymbolMarkers.kt @@ -25,4 +25,4 @@ interface TypeParameterSymbolMarker : ClassifierSymbolMarker interface ClassLikeSymbolMarker : ClassifierSymbolMarker interface RegularClassSymbolMarker : ClassLikeSymbolMarker interface TypeAliasSymbolMarker : ClassLikeSymbolMarker - +interface K1SyntheticClassifierSymbolMarker : ClassifierSymbolMarker