[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
This commit is contained in:
Dmitriy Novozhilov
2022-12-06 11:15:28 +02:00
committed by Space Team
parent 2aad466d00
commit 880b278c40
3 changed files with 52 additions and 9 deletions
@@ -6,11 +6,11 @@ FILE: kt55286.kt
}
public open class Base : R|kotlin/Any| {
public constructor(@R|Deprecated<ERROR CLASS: Symbol not found for Nested>|() a: R|kotlin/String|): R|Base| {
public constructor(@R|Deprecated<Base.Nested>|() a: R|kotlin/String|): R|Base| {
super<R|kotlin/Any|>()
}
@R|Deprecated<ERROR CLASS: Symbol not found for Nested>|() public final val a: R|kotlin/String| = R|<local>/a|
@R|Deprecated<Base.Nested>|() public final val a: R|kotlin/String| = R|<local>/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<ERROR CLASS: Symbol not found for Nested>|() b: R|kotlin/String|): R|Derived| {
public constructor(@R|Deprecated<Base.Nested>|() b: R|kotlin/String|): R|Derived| {
super<R|Base|>(String())
}
@R|Deprecated<ERROR CLASS: Symbol not found for Nested>|() public final val b: R|kotlin/String| = R|<local>/b|
@R|Deprecated<Base.Nested>|() public final val b: R|kotlin/String| = R|<local>/b|
public get(): R|kotlin/String|
}
@@ -3,11 +3,11 @@
annotation class Deprecated<T>
open class Base(
@Deprecated<<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Nested<!>> val a: String,
@Deprecated<Nested> val a: String,
) {
class Nested
}
class Derived(
@Deprecated<<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Nested<!>> val b: String,
@Deprecated<Nested> val b: String,
) : Base("")
@@ -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<FirDeclaration>?) {
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()
}
}
}