From 880b278c40de1ae96a66898dd49705134e34e36b Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 6 Dec 2022 11:15:28 +0200 Subject: [PATCH] [FIR] Deeply copy annotation type ref on COMPILER_REQUIRED_ANNOTATION_PHASE The original idea was in resolving of annotation type ref using only importing scopes and accepting or discarding that resolution result depending on if this annotation is needed for compiler/plugins or not But there is a problem that resolution of FirUserType with type resolver is not a pure operation: type resolver transforms qualifier parts which may contain type arguments, so if they were unresolved at the first resolve, they will stay unresolved forever. To prevent this we will deeply copy annotation type ref before first resolution ^KT-55286 Fixed --- .../resolve/annotations/kt55286.fir.txt | 8 +-- .../testData/resolve/annotations/kt55286.kt | 4 +- ...FirSpecificAnnotationResolveTransformer.kt | 49 +++++++++++++++++-- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.fir.txt b/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.fir.txt index f02e0bd3fdd..2ac69a60292 100644 --- a/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.fir.txt @@ -6,11 +6,11 @@ FILE: kt55286.kt } public open class Base : R|kotlin/Any| { - public constructor(@R|Deprecated|() a: R|kotlin/String|): R|Base| { + public constructor(@R|Deprecated|() a: R|kotlin/String|): R|Base| { super() } - @R|Deprecated|() public final val a: R|kotlin/String| = R|/a| + @R|Deprecated|() public final val a: R|kotlin/String| = R|/a| public get(): R|kotlin/String| public final class Nested : R|kotlin/Any| { @@ -22,11 +22,11 @@ FILE: kt55286.kt } public final class Derived : R|Base| { - public constructor(@R|Deprecated|() b: R|kotlin/String|): R|Derived| { + public constructor(@R|Deprecated|() b: R|kotlin/String|): R|Derived| { super(String()) } - @R|Deprecated|() public final val b: R|kotlin/String| = R|/b| + @R|Deprecated|() public final val b: R|kotlin/String| = R|/b| public get(): R|kotlin/String| } diff --git a/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.kt b/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.kt index 8040eecf4c1..1e6d8c52b2e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.kt +++ b/compiler/fir/analysis-tests/testData/resolve/annotations/kt55286.kt @@ -3,11 +3,11 @@ annotation class Deprecated open class Base( - @Deprecated<Nested> val a: String, + @Deprecated val a: String, ) { class Nested } class Derived( - @Deprecated<Nested> val b: String, + @Deprecated val b: String, ) : Base("") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt index b8bd38a6cc8..bda75c89c24 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt @@ -27,6 +27,12 @@ import org.jetbrains.kotlin.fir.resolve.transformers.withClassDeclarationCleanup import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.createImportingScopes import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.builder.buildPlaceholderProjection +import org.jetbrains.kotlin.fir.types.builder.buildStarProjection +import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance +import org.jetbrains.kotlin.fir.types.builder.buildUserTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirQualifierPartImpl +import org.jetbrains.kotlin.fir.types.impl.FirTypeArgumentListImpl import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.ClassId @@ -35,6 +41,7 @@ import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Deprecated import org.jetbrains.kotlin.name.StandardClassIds.Annotations.DeprecatedSinceKotlin import org.jetbrains.kotlin.name.StandardClassIds.Annotations.JvmRecord import org.jetbrains.kotlin.name.StandardClassIds.Annotations.WasExperimental +import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled internal abstract class AbstractFirSpecificAnnotationResolveTransformer( protected val session: FirSession, @@ -76,8 +83,8 @@ internal abstract class AbstractFirSpecificAnnotationResolveTransformer( if (!shouldRunAnnotationResolve(name)) return annotationCall - val transformedAnnotationType = annotationCall.typeRef.transformSingle( - typeResolverTransformer, + val transformedAnnotationType = typeResolverTransformer.transformUserTypeRef( + annotationTypeRef.createDeepCopy(), ScopeClassDeclaration(scopes.asReversed(), classDeclarationsStack) ) as? FirResolvedTypeRef ?: return annotationCall @@ -274,11 +281,47 @@ internal abstract class AbstractFirSpecificAnnotationResolveTransformer( * Gets called after performing transformation of some declaration's nested declarations; can be used to restore the internal * state of the transformer. * - * @param parentDeclaration A declaration whose nested declarations were transformed. * @param state A state produced by the [beforeTransformingChildren] call before the transformation. */ private fun afterTransformingChildren(state: PersistentList?) { requireNotNull(state) owners = state } + + private fun FirUserTypeRef.createDeepCopy(): FirUserTypeRef { + val original = this + return buildUserTypeRef { + source = original.source + isMarkedNullable = original.isMarkedNullable + annotations.addAll(original.annotations) + original.qualifier.mapTo(qualifier) { it.createDeepCopy() } + } + } + + private fun FirQualifierPart.createDeepCopy(): FirQualifierPart { + val newArgumentList = FirTypeArgumentListImpl(typeArgumentList.source).apply { + typeArgumentList.typeArguments.mapTo(typeArguments) { it.createDeepCopy() } + } + return FirQualifierPartImpl( + source, + name, + newArgumentList + ) + } + + private fun FirTypeProjection.createDeepCopy(): FirTypeProjection { + return when (val original = this) { + is FirTypeProjectionWithVariance -> buildTypeProjectionWithVariance { + source = original.source + typeRef = when (val originalTypeRef = original.typeRef) { + is FirUserTypeRef -> originalTypeRef.createDeepCopy() + else -> originalTypeRef + } + variance = original.variance + } + is FirStarProjection -> buildStarProjection { source = original.source } + is FirPlaceholderProjection -> buildPlaceholderProjection { source = original.source } + else -> shouldNotBeCalled() + } + } }