[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");
}
@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 {
@@ -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 {
@@ -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)
@@ -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 }
}
@@ -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
@@ -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
}
}
@@ -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)
@@ -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<T : DeclarationSymbolMarker> : TypeSystemC
fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean
val DeclarationSymbolMarker.hasSourceAnnotationsErased: Boolean
interface AnnotationCallInfo {
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.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
}
}
@@ -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");
}
@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 {
@@ -25,4 +25,4 @@ interface TypeParameterSymbolMarker : ClassifierSymbolMarker
interface ClassLikeSymbolMarker : ClassifierSymbolMarker
interface RegularClassSymbolMarker : ClassLikeSymbolMarker
interface TypeAliasSymbolMarker : ClassLikeSymbolMarker
interface K1SyntheticClassifierSymbolMarker : ClassifierSymbolMarker