[FE, IR] Don't check SOURCE annotations if actual declaration has no source

^KT-58551
This commit is contained in:
Roman Efremov
2023-06-23 14:43:29 +02:00
committed by Space Team
parent 59f1a0dd8e
commit 234f453173
13 changed files with 135 additions and 10 deletions
@@ -286,6 +286,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); 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 @Test
@TestMetadata("typealias.kt") @TestMetadata("typealias.kt")
public void testTypealias() throws Exception { public void testTypealias() throws Exception {
@@ -286,6 +286,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); 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 @Test
@TestMetadata("typealias.kt") @TestMetadata("typealias.kt")
public void testTypealias() throws Exception { public void testTypealias() throws Exception {
@@ -11,13 +11,13 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContextFactory import org.jetbrains.kotlin.fir.FirExpectActualMatchingContextFactory
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.getRetention
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
import org.jetbrains.kotlin.fir.resolve.* 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.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -353,8 +353,20 @@ class FirExpectActualMatchingContextImpl private constructor(
private inner class AnnotationCallInfoImpl(val annotation: FirAnnotation) : AnnotationCallInfo { private inner class AnnotationCallInfoImpl(val annotation: FirAnnotation) : AnnotationCallInfo {
override val classId: ClassId? override val classId: ClassId?
get() = annotation.toAnnotationClassId(actualSession) 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 { object Factory : FirExpectActualMatchingContextFactory {
override fun create(session: FirSession, scopeSession: ScopeSession): FirExpectActualMatchingContextImpl = override fun create(session: FirSession, scopeSession: ScopeSession): FirExpectActualMatchingContextImpl =
FirExpectActualMatchingContextImpl(session, scopeSession) FirExpectActualMatchingContextImpl(session, scopeSession)
@@ -6,19 +6,22 @@
package org.jetbrains.kotlin.fir.analysis package org.jetbrains.kotlin.fir.analysis
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.*
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.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.toResolvedEnumEntrySymbol 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 import org.jetbrains.kotlin.name.StandardClassIds
fun FirRegularClass.getRetention(session: FirSession): AnnotationRetention { fun FirRegularClass.getRetention(session: FirSession): AnnotationRetention {
return getRetentionAnnotation(session)?.getRetention() ?: AnnotationRetention.RUNTIME return getRetentionAnnotation(session)?.getRetention() ?: AnnotationRetention.RUNTIME
} }
fun FirRegularClassSymbol.getRetention(session: FirSession): AnnotationRetention {
return getRetentionAnnotation(session)?.getRetention() ?: AnnotationRetention.RUNTIME
}
fun FirAnnotation.getRetention(): AnnotationRetention? { fun FirAnnotation.getRetention(): AnnotationRetention? {
val propertyAccess = findArgumentByName(StandardClassIds.Annotations.ParameterNames.retentionValue) as? FirQualifiedAccessExpression val propertyAccess = findArgumentByName(StandardClassIds.Annotations.ParameterNames.retentionValue) as? FirQualifiedAccessExpression
val callableId = propertyAccess?.calleeReference?.toResolvedEnumEntrySymbol()?.callableId ?: return null val callableId = propertyAccess?.calleeReference?.toResolvedEnumEntrySymbol()?.callableId ?: return null
@@ -33,3 +36,11 @@ fun FirAnnotation.getRetention(): AnnotationRetention? {
fun FirDeclaration.getRetentionAnnotation(session: FirSession): FirAnnotation? { fun FirDeclaration.getRetentionAnnotation(session: FirSession): FirAnnotation? {
return getAnnotationByClassId(StandardClassIds.Annotations.Retention, session) 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 }
}
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase
import org.jetbrains.kotlin.mpp.K1SyntheticClassifierSymbolMarker
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -50,7 +51,8 @@ class SyntheticClassOrObjectDescriptor(
constructorVisibility: DescriptorVisibility, constructorVisibility: DescriptorVisibility,
private val kind: ClassKind, private val kind: ClassKind,
private val isCompanionObject: Boolean 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()) val syntheticDeclaration: KtPureClassOrObject = SyntheticDeclaration(parentClassOrObject, name.asString())
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
@@ -5,13 +5,14 @@
package org.jetbrains.kotlin.backend.common.actualizer 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.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall 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.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -464,5 +465,17 @@ internal abstract class IrExpectActualMatchingContext(
private class AnnotationCallInfoImpl(val irElement: IrConstructorCall) : AnnotationCallInfo { private class AnnotationCallInfoImpl(val irElement: IrConstructorCall) : AnnotationCallInfo {
override val classId: ClassId? override val classId: ClassId?
get() = irElement.type.getClass()?.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
}
} }
@@ -28,12 +28,16 @@ object AbstractExpectActualAnnotationMatchChecker {
return areAnnotationsCompatible(expectSymbol, expanded) return areAnnotationsCompatible(expectSymbol, expanded)
} }
val skipSourceAnnotations = !actualSymbol.hasSourceAnnotationsErased
val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId } val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId }
for (expectAnnotation in expectSymbol.annotations) { for (expectAnnotation in expectSymbol.annotations) {
if (expectAnnotation.classId == StandardClassIds.Annotations.OptionalExpectation) { if (expectAnnotation.classId == StandardClassIds.Annotations.OptionalExpectation) {
continue continue
} }
if (expectAnnotation.isRetentionSource && skipSourceAnnotations) {
continue
}
val actualAnnotationsWithSameClassId = actualAnnotationsByName[expectAnnotation.classId] ?: emptyList() val actualAnnotationsWithSameClassId = actualAnnotationsByName[expectAnnotation.classId] ?: emptyList()
if (actualAnnotationsWithSameClassId.none { areAnnotationArgumentsEqual(expectAnnotation, it) }) { if (actualAnnotationsWithSameClassId.none { areAnnotationArgumentsEqual(expectAnnotation, it) }) {
return Incompatibility(expectSymbol, actualSymbol) return Incompatibility(expectSymbol, actualSymbol)
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.mpp.* import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
@@ -163,7 +162,10 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean
val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean
interface AnnotationCallInfo { interface AnnotationCallInfo {
val classId: ClassId? val classId: ClassId?
val isRetentionSource: Boolean
} }
} }
@@ -22,7 +22,10 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.* 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.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
import org.jetbrains.kotlin.utils.addToStdlib.castAll import org.jetbrains.kotlin.utils.addToStdlib.castAll
@@ -345,5 +348,15 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) :
) : AnnotationCallInfo { ) : AnnotationCallInfo {
override val classId: ClassId? override val classId: ClassId?
get() = annotationDescriptor.annotationClass?.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
}
} }
@@ -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_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>SourceAvailable<!> = SourceAvailableImpl<!>
actual typealias FromLib = kotlin.SinceKotlin
@@ -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 <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>SourceAvailable<!> = SourceAvailableImpl
actual typealias FromLib = kotlin.SinceKotlin
@@ -22831,6 +22831,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/optionalExpectation.kt"); 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 @Test
@TestMetadata("typealias.kt") @TestMetadata("typealias.kt")
public void testTypealias() throws Exception { public void testTypealias() throws Exception {
@@ -25,4 +25,4 @@ interface TypeParameterSymbolMarker : ClassifierSymbolMarker
interface ClassLikeSymbolMarker : ClassifierSymbolMarker interface ClassLikeSymbolMarker : ClassifierSymbolMarker
interface RegularClassSymbolMarker : ClassLikeSymbolMarker interface RegularClassSymbolMarker : ClassLikeSymbolMarker
interface TypeAliasSymbolMarker : ClassLikeSymbolMarker interface TypeAliasSymbolMarker : ClassLikeSymbolMarker
interface K1SyntheticClassifierSymbolMarker : ClassifierSymbolMarker