[FIR] Lazy resolve annotation calls before accessing customAnnotations
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/KtFirAnnotationListForType.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/KtFirAnnotationListForType.kt
index edca47c..b72018d 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/KtFirAnnotationListForType.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/KtFirAnnotationListForType.kt
@@ -12,8 +12,13 @@
 import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
 import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
 import org.jetbrains.kotlin.fir.declarations.fullyExpandedClassId
+import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
+import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
+import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
 import org.jetbrains.kotlin.fir.types.ConeKotlinType
+import org.jetbrains.kotlin.fir.types.custom
 import org.jetbrains.kotlin.fir.types.customAnnotations
 import org.jetbrains.kotlin.name.ClassId
 
@@ -46,11 +51,21 @@
             useSiteSession: FirSession,
             token: KtLifetimeToken,
         ): KtAnnotationsList {
-            return if (coneType.customAnnotations.isEmpty()) {
-                KtEmptyAnnotationsList(token)
-            } else {
-                KtFirAnnotationListForType(coneType, useSiteSession, token)
+            if (coneType.customAnnotations.isEmpty()) {
+                return KtEmptyAnnotationsList(token)
             }
+
+            if (coneType.attributes.custom?.owningSymbol == null) {
+                val hasAnnotationsWithUnresolvedArguments = coneType.customAnnotations.filterIsInstance<FirAnnotationCall>()
+                    .any { it.argumentList !is FirResolvedArgumentList }
+
+                if (hasAnnotationsWithUnresolvedArguments) {
+                    error("$coneType has annotations with unresolved arguments mapping, but no symbol responsible for their resolution")
+                }
+            }
+
+            coneType.attributes.custom?.owningSymbol?.lazyResolveToPhase(FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING)
+            return KtFirAnnotationListForType(coneType, useSiteSession, token)
         }
     }
 }
diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt
index f2b524a..f1a2c682 100644
--- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt
+++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt
@@ -124,7 +124,7 @@
         val classDeserializer = context.memberDeserializer
 
         val superTypesDeserialized = classProto.supertypes(context.typeTable).map { supertypeProto ->
-            typeDeserializer.simpleType(supertypeProto, ConeAttributes.Empty)
+            typeDeserializer.simpleType(supertypeProto, ConeAttributes.Empty, symbol)
         }
 
         superTypesDeserialized.mapNotNullTo(superTypeRefs) {
@@ -209,7 +209,7 @@
         })
         companionObjectSymbol = (declarations.firstOrNull { it is FirRegularClass && it.isCompanion } as FirRegularClass?)?.symbol
 
-        contextReceivers.addAll(classDeserializer.createContextReceiversForClass(classProto))
+        contextReceivers.addAll(classDeserializer.createContextReceiversForClass(classProto, symbol))
     }.also {
         if (isSealed) {
             val inheritors = classProto.sealedSubclassFqNameList.map { nameIndex ->
diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt
index ad65d9f..a0dc84f 100644
--- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt
+++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt
@@ -15,6 +15,9 @@
 import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
 import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
 import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
+import org.jetbrains.kotlin.fir.resolve.dfa.DfaInternals
+import org.jetbrains.kotlin.fir.resolve.dfa.symbol
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.types.ConeAttributes
 import org.jetbrains.kotlin.fir.types.ConeKotlinType
 import org.jetbrains.kotlin.fir.types.isBoolean
@@ -93,6 +96,7 @@
         }
     }
 
+    @OptIn(DfaInternals::class)
     private fun extractPrimitiveExpression(proto: ProtoBuf.Expression, primitiveType: PrimitiveExpressionType?, owner: FirContractDescriptionOwner): ConeBooleanExpression? {
         val isInverted = Flags.IS_NEGATED.get(proto.flags)
 
@@ -106,7 +110,7 @@
 
             PrimitiveExpressionType.INSTANCE_CHECK -> {
                 val variable = extractVariable(proto, owner) ?: return null
-                val type = extractType(proto) ?: return null
+                val type = extractType(proto, owner.symbol) ?: return null
                 ConeIsInstancePredicate(variable, type, isInverted)
             }
 
@@ -151,8 +155,8 @@
         ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> EventOccurrencesRange.AT_LEAST_ONCE
     }
 
-    private fun extractType(proto: ProtoBuf.Expression): ConeKotlinType? {
-        return c.typeDeserializer.type(proto.isInstanceType(c.typeTable) ?: return null)
+    private fun extractType(proto: ProtoBuf.Expression, owningSymbol: FirBasedSymbol<*>?): ConeKotlinType? {
+        return c.typeDeserializer.type(proto.isInstanceType(c.typeTable) ?: return null, owningSymbol)
     }
 
     private fun loadConstant(value: ProtoBuf.Expression.ConstantValue): ConeConstantReference? = when (value) {
diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt
index 6c55e5c..1a6fce2 100644
--- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt
+++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt
@@ -213,7 +213,7 @@
 
             annotations += c.annotationDeserializer.loadTypeAliasAnnotations(proto, local.nameResolver)
             this.symbol = symbol
-            expandedTypeRef = proto.underlyingType(c.typeTable).toTypeRef(local)
+            expandedTypeRef = proto.underlyingType(c.typeTable).toTypeRef(local, symbol)
             resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
             typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
         }.apply {
@@ -349,7 +349,7 @@
             false, false, false
         )
 
-        val returnTypeRef = proto.returnType(c.typeTable).toTypeRef(local)
+        val returnTypeRef = proto.returnType(c.typeTable).toTypeRef(local, symbol)
 
         val hasGetter = Flags.HAS_GETTER.get(flags)
         val receiverAnnotations = if (hasGetter && proto.hasReceiver()) {
@@ -367,7 +367,7 @@
             moduleData = c.moduleData
             origin = FirDeclarationOrigin.Library
             this.returnTypeRef = returnTypeRef
-            receiverTypeRef = proto.receiverType(c.typeTable)?.toTypeRef(local).apply {
+            receiverTypeRef = proto.receiverType(c.typeTable)?.toTypeRef(local, symbol).apply {
                 annotations += receiverAnnotations
             }
             name = callableName
@@ -424,14 +424,14 @@
             this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver)
             deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(fromJava = false, c.session.firCachesFactory)
 
-            proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver)
+            proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers) { loadContextReceiver(it, symbol) }
         }.apply {
             versionRequirementsTable = c.versionRequirementTable
         }
     }
 
-    private fun loadContextReceiver(proto: ProtoBuf.Type): FirContextReceiver {
-        val typeRef = proto.toTypeRef(c)
+    private fun loadContextReceiver(proto: ProtoBuf.Type, owningSymbol: FirBasedSymbol<*>): FirContextReceiver {
+        val typeRef = proto.toTypeRef(c, owningSymbol)
         return buildContextReceiver {
             val type = typeRef.coneType
             this.labelNameFromTypeRef = (type as? ConeLookupTagBasedType)?.lookupTag?.name
@@ -439,8 +439,8 @@
         }
     }
 
-    internal fun createContextReceiversForClass(classProto: ProtoBuf.Class): List<FirContextReceiver> =
-        classProto.contextReceiverTypes(c.typeTable).map(::loadContextReceiver)
+    internal fun createContextReceiversForClass(classProto: ProtoBuf.Class, owningSymbol: FirBasedSymbol<*>): List<FirContextReceiver> =
+        classProto.contextReceiverTypes(c.typeTable).map { loadContextReceiver(it, owningSymbol) }
 
     fun loadFunction(
         proto: ProtoBuf.Function,
@@ -467,8 +467,8 @@
         val simpleFunction = buildSimpleFunction {
             moduleData = c.moduleData
             origin = deserializationOrigin
-            returnTypeRef = proto.returnType(local.typeTable).toTypeRef(local)
-            receiverTypeRef = proto.receiverType(local.typeTable)?.toTypeRef(local).apply {
+            returnTypeRef = proto.returnType(local.typeTable).toTypeRef(local, symbol)
+            receiverTypeRef = proto.receiverType(local.typeTable)?.toTypeRef(local, symbol).apply {
                 annotations += receiverAnnotations
             }
             name = callableName
@@ -503,7 +503,7 @@
             deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(fromJava = false, c.session.firCachesFactory)
             this.containerSource = c.containerSource
 
-            proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver)
+            proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers) { loadContextReceiver(it, symbol) }
         }.apply {
             versionRequirementsTable = c.versionRequirementTable
         }
@@ -581,7 +581,7 @@
             containerSource = c.containerSource
             deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(fromJava = false, c.session.firCachesFactory)
 
-            contextReceivers.addAll(createContextReceiversForClass(classProto))
+            contextReceivers.addAll(createContextReceiversForClass(classProto, symbol))
         }.build().apply {
             containingClassForStaticMemberAttr = c.dispatchReceiver!!.lookupTag
             versionRequirementsTable = c.versionRequirementTable
@@ -608,9 +608,9 @@
             buildValueParameter {
                 moduleData = c.moduleData
                 origin = FirDeclarationOrigin.Library
-                returnTypeRef = proto.type(c.typeTable).toTypeRef(c)
                 this.name = name
                 symbol = FirValueParameterSymbol(name)
+                returnTypeRef = proto.type(c.typeTable).toTypeRef(c, symbol)
                 resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
                 defaultValue = defaultValue(flags)
                 if (addDefaultValue) {
@@ -635,11 +635,11 @@
         }.toList()
     }
 
-    private fun ProtoBuf.Type.toTypeRef(context: FirDeserializationContext): FirTypeRef {
+    private fun ProtoBuf.Type.toTypeRef(context: FirDeserializationContext, owningSymbol: FirBasedSymbol<*>): FirTypeRef {
         return buildResolvedTypeRef {
             annotations += context.annotationDeserializer.loadTypeAnnotations(this@toTypeRef, context.nameResolver)
-            val attributes = annotations.computeTypeAttributes(context.session)
-            type = context.typeDeserializer.type(this@toTypeRef, attributes)
+            val attributes = annotations.computeTypeAttributes(context.session, owningSymbol = owningSymbol)
+            type = context.typeDeserializer.type(this@toTypeRef, attributes, owningSymbol)
         }
     }
 }
diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt
index c9050e9..29654fe 100644
--- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt
+++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt
@@ -84,7 +84,7 @@
                 val builder = builders[index]
                 builder.apply {
                     proto.upperBounds(typeTable).mapTo(bounds) {
-                        buildResolvedTypeRef { type = type(it) }
+                        buildResolvedTypeRef { type = type(it, builder.containingDeclarationSymbol) }
                     }
                     addDefaultBoundIfNecessary()
                 }.build()
@@ -105,16 +105,16 @@
         }
     }
 
-    fun type(proto: ProtoBuf.Type): ConeKotlinType {
+    fun type(proto: ProtoBuf.Type, owningSymbol: FirBasedSymbol<*>?): ConeKotlinType {
         val annotations = annotationDeserializer.loadTypeAnnotations(proto, nameResolver)
-        val attributes = annotations.computeTypeAttributes(moduleData.session)
-        return type(proto, attributes)
+        val attributes = annotations.computeTypeAttributes(moduleData.session, owningSymbol = owningSymbol)
+        return type(proto, attributes, owningSymbol)
     }
 
-    fun type(proto: ProtoBuf.Type, attributes: ConeAttributes): ConeKotlinType {
+    fun type(proto: ProtoBuf.Type, attributes: ConeAttributes, owningSymbol: FirBasedSymbol<*>?): ConeKotlinType {
         if (proto.hasFlexibleTypeCapabilitiesId()) {
-            val lowerBound = simpleType(proto, attributes)
-            val upperBound = simpleType(proto.flexibleUpperBound(typeTable)!!, attributes)
+            val lowerBound = simpleType(proto, attributes, owningSymbol)
+            val upperBound = simpleType(proto.flexibleUpperBound(typeTable)!!, attributes, owningSymbol)
 
             val isDynamic = lowerBound == moduleData.session.builtinTypes.nothingType.coneType &&
                     upperBound == moduleData.session.builtinTypes.nullableAnyType.coneType
@@ -126,7 +126,8 @@
             }
         }
 
-        return simpleType(proto, attributes) ?: ConeErrorType(ConeSimpleDiagnostic("?!id:0", DiagnosticKind.DeserializationError))
+        return simpleType(proto, attributes, owningSymbol)
+            ?: ConeErrorType(ConeSimpleDiagnostic("?!id:0", DiagnosticKind.DeserializationError))
     }
 
     private fun typeParameterSymbol(typeParameterId: Int): ConeTypeParameterLookupTag? =
@@ -144,7 +145,7 @@
     fun FirClassLikeSymbol<*>.typeParameters(): List<FirTypeParameterSymbol> =
         (fir as? FirTypeParameterRefsOwner)?.typeParameters?.map { it.symbol }.orEmpty()
 
-    fun simpleType(proto: ProtoBuf.Type, attributes: ConeAttributes): ConeSimpleKotlinType? {
+    fun simpleType(proto: ProtoBuf.Type, attributes: ConeAttributes, owningSymbol: FirBasedSymbol<*>?): ConeSimpleKotlinType? {
         val constructor = typeSymbol(proto) ?: return null
         if (constructor is ConeTypeParameterLookupTag) {
             return ConeTypeParameterTypeImpl(constructor, isNullable = proto.nullable).let {
@@ -159,14 +160,14 @@
         fun ProtoBuf.Type.collectAllArguments(): List<ProtoBuf.Type.Argument> =
             argumentList + outerType(typeTable)?.collectAllArguments().orEmpty()
 
-        val arguments = proto.collectAllArguments().map(this::typeArgument).toTypedArray()
+        val arguments = proto.collectAllArguments().map { typeArgument(it, owningSymbol) }.toTypedArray()
         val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
             createSuspendFunctionType(constructor, arguments, isNullable = proto.nullable, attributes)
         } else {
             ConeClassLikeTypeImpl(constructor, arguments, isNullable = proto.nullable, attributes)
         }
         val abbreviatedTypeProto = proto.abbreviatedType(typeTable) ?: return simpleType
-        return simpleType(abbreviatedTypeProto, attributes)
+        return simpleType(abbreviatedTypeProto, attributes, owningSymbol)
     }
 
     private fun createSuspendFunctionTypeForBasicCase(
@@ -241,7 +242,7 @@
     }
 
 
-    private fun typeArgument(typeArgumentProto: ProtoBuf.Type.Argument): ConeTypeProjection {
+    private fun typeArgument(typeArgumentProto: ProtoBuf.Type.Argument, owningSymbol: FirBasedSymbol<*>?): ConeTypeProjection {
         if (typeArgumentProto.projection == ProtoBuf.Type.Argument.Projection.STAR) {
             return ConeStarProjection
         }
@@ -249,7 +250,7 @@
         val variance = ProtoEnumFlags.variance(typeArgumentProto.projection)
         val type = typeArgumentProto.type(typeTable)
             ?: return ConeErrorType(ConeSimpleDiagnostic("No type recorded", DiagnosticKind.DeserializationError))
-        val coneType = type(type)
+        val coneType = type(type, owningSymbol)
         return coneType.toTypeProjection(variance)
     }
 }
diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt
index 6287684..2a323f5 100644
--- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt
+++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt
@@ -99,7 +99,7 @@
             }
         }
 
-        ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(convertedAnnotations)))
+        ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(convertedAnnotations, owningSymbol = null)))
     } else {
         ConeAttributes.Empty
     }
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt
index bc47b5b..d3e7640 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt
@@ -98,8 +98,8 @@
                 buildConstExpression(fakeSource, ConstantValueKind.String, valueParameter.name.asString(), setType = true)
         }
     }
-    val attributesWithParameterNameAnnotation =
-        ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(listOf(parameterNameAnnotationCall))))
+    val attribute = CustomAnnotationTypeAttribute(listOf(parameterNameAnnotationCall), owningSymbol = valueParameter.symbol)
+    val attributesWithParameterNameAnnotation = ConeAttributes.create(listOf(attribute))
     return withCombinedAttributesFrom(attributesWithParameterNameAnnotation)
 }
 
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt
index bfde838..ffe7687 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt
@@ -223,7 +223,8 @@
         result: TypeResolutionResult,
         areBareTypesAllowed: Boolean,
         topContainer: FirDeclaration?,
-        isOperandOfIsOperator: Boolean
+        isOperandOfIsOperator: Boolean,
+        owningSymbol: FirBasedSymbol<*>?,
     ): ConeKotlinType {
 
         val (symbol, substitutor) = when (result) {
@@ -250,7 +251,7 @@
                     ConeUnresolvedQualifierError(typeRef.render())
                 }
             }
-            return ConeErrorType(diagnostic, attributes = typeRef.annotations.computeTypeAttributes(session))
+            return ConeErrorType(diagnostic, attributes = typeRef.annotations.computeTypeAttributes(session, owningSymbol = owningSymbol))
         }
         if (symbol is FirTypeParameterSymbol) {
             for (part in typeRef.qualifier) {
@@ -353,7 +354,7 @@
         return symbol.constructType(
             allTypeArguments.toTypedArray(),
             typeRef.isMarkedNullable,
-            typeRef.annotations.computeTypeAttributes(session)
+            typeRef.annotations.computeTypeAttributes(session, owningSymbol = owningSymbol)
         ).also {
             val lookupTag = it.lookupTag
             if (lookupTag is ConeClassLikeLookupTagImpl && symbol is FirClassLikeSymbol<*>) {
@@ -462,7 +463,7 @@
         }
     }
 
-    private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType {
+    private fun createFunctionalType(typeRef: FirFunctionTypeRef, owningSymbol: FirBasedSymbol<*>?): ConeClassLikeType {
         val parameters =
             typeRef.contextReceiverTypeRefs.map { it.coneType } +
                     listOfNotNull(typeRef.receiverTypeRef?.coneType) +
@@ -484,7 +485,8 @@
                 if (typeRef.contextReceiverTypeRefs.isNotEmpty()) {
                     add(CompilerConeAttributes.ContextFunctionTypeParams(typeRef.contextReceiverTypeRefs.size))
                 }
-            }
+            },
+            owningSymbol = owningSymbol,
         )
         val symbol = resolveBuiltInQualified(classId, session)
         return ConeClassLikeTypeImpl(
@@ -516,10 +518,11 @@
                     result,
                     areBareTypesAllowed,
                     scopeClassDeclaration.topContainer ?: scopeClassDeclaration.containingDeclarations.lastOrNull(),
-                    isOperandOfIsOperator
+                    isOperandOfIsOperator,
+                    scopeClassDeclaration.owningSymbol,
                 ) to (result as? TypeResolutionResult.Resolved)?.typeCandidate?.diagnostic
             }
-            is FirFunctionTypeRef -> createFunctionalType(typeRef) to null
+            is FirFunctionTypeRef -> createFunctionalType(typeRef, scopeClassDeclaration.owningSymbol) to null
             is FirDynamicTypeRef -> ConeDynamicType.create(session) to null
             is FirIntersectionTypeRef -> {
                 val leftType = typeRef.leftType.coneType
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt
index 4335281..29b7f5d 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt
@@ -366,7 +366,7 @@
         val resolvedTypesRefs = transformer.withFile(useSiteFile) {
             resolveSuperTypeRefs(
                 transformer,
-                ScopeClassDeclaration(scopes, classDeclarationsStack)
+                ScopeClassDeclaration(scopes, classDeclarationsStack, classLikeDeclaration.symbol)
             )
         }
 
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt
index ee96cb9..037755e 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt
@@ -10,6 +10,7 @@
 import org.jetbrains.kotlin.fir.declarations.*
 import org.jetbrains.kotlin.fir.declarations.utils.isFromVararg
 import org.jetbrains.kotlin.fir.expressions.*
+import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
 import org.jetbrains.kotlin.fir.resolve.ScopeSession
 import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeCyclicTypeBound
 import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
@@ -19,6 +20,7 @@
 import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
 import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
 import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.types.*
 import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
 
@@ -61,6 +63,18 @@
         scopes.addAll(initialScopes.asReversed())
     }
 
+    private var owningSymbol: FirBasedSymbol<*>? = classDeclarationsStack.lastOrNull()?.symbol ?: initialCurrentFile?.symbol
+
+    private inline fun <R> withOwningSymbol(symbol: FirBasedSymbol<*>, block: () -> R): R {
+        val oldOwningSymbol = owningSymbol
+        return try {
+            owningSymbol = symbol
+            block()
+        } finally {
+            owningSymbol = oldOwningSymbol
+        }
+    }
+
     private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(session)
     private var currentFile: FirFile? = initialCurrentFile
 
@@ -68,28 +82,34 @@
         checkSessionConsistency(file)
         currentFile = file
         return withScopeCleanup {
-            scopes.addAll(createImportingScopes(file, session, scopeSession))
-            super.transformFile(file, data)
+            withOwningSymbol(file.symbol) {
+                scopes.addAll(createImportingScopes(file, session, scopeSession))
+                super.transformFile(file, data)
+            }
         }
     }
 
     override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): FirStatement {
         withClassDeclarationCleanup(classDeclarationsStack, regularClass) {
-            withScopeCleanup {
-                regularClass.addTypeParametersScope()
-                regularClass.typeParameters.forEach {
-                    it.accept(this, data)
+            withOwningSymbol(regularClass.symbol) {
+                withScopeCleanup {
+                    regularClass.addTypeParametersScope()
+                    regularClass.typeParameters.forEach {
+                        it.accept(this, data)
+                    }
+                    unboundCyclesInTypeParametersSupertypes(regularClass)
                 }
-                unboundCyclesInTypeParametersSupertypes(regularClass)
-            }
 
-            return resolveClassContent(regularClass, data)
+                return resolveClassContent(regularClass, data)
+            }
         }
     }
 
     override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): FirStatement {
         withClassDeclarationCleanup(classDeclarationsStack, anonymousObject) {
-            return resolveClassContent(anonymousObject, data)
+            withOwningSymbol(anonymousObject.symbol) {
+                return resolveClassContent(anonymousObject, data)
+            }
         }
     }
 
@@ -108,36 +128,40 @@
     }
 
     override fun transformEnumEntry(enumEntry: FirEnumEntry, data: Any?): FirEnumEntry {
-        enumEntry.transformReturnTypeRef(this, data)
-        enumEntry.transformTypeParameters(this, data)
-        enumEntry.transformAnnotations(this, data)
-        return enumEntry
+        withOwningSymbol(enumEntry.symbol) {
+            enumEntry.transformReturnTypeRef(this, data)
+            enumEntry.transformTypeParameters(this, data)
+            enumEntry.transformAnnotations(this, data)
+            return enumEntry
+        }
     }
 
     override fun transformProperty(property: FirProperty, data: Any?): FirProperty {
-        return withScopeCleanup {
-            property.addTypeParametersScope()
-            property.transformTypeParameters(this, data)
-                .transformReturnTypeRef(this, data)
-                .transformReceiverTypeRef(this, data)
-                .transformContextReceivers(this, data)
-                .transformGetter(this, data)
-                .transformSetter(this, data)
-                .transformBackingField(this, data)
-                .transformAnnotations(this, data)
-            if (property.isFromVararg == true) {
-                property.transformTypeToArrayType()
-                property.backingField?.transformTypeToArrayType()
-                setAccessorTypesByPropertyType(property)
+        return withOwningSymbol(property.symbol) {
+            withScopeCleanup {
+                property.addTypeParametersScope()
+                property.transformTypeParameters(this, data)
+                    .transformReturnTypeRef(this, data)
+                    .transformReceiverTypeRef(this, data)
+                    .transformContextReceivers(this, data)
+                    .transformGetter(this, data)
+                    .transformSetter(this, data)
+                    .transformBackingField(this, data)
+                    .transformAnnotations(this, data)
+                if (property.isFromVararg == true) {
+                    property.transformTypeToArrayType()
+                    property.backingField?.transformTypeToArrayType()
+                    setAccessorTypesByPropertyType(property)
+                }
+
+                if (property.returnTypeRef is FirResolvedTypeRef && property.delegate != null) {
+                    setAccessorTypesByPropertyType(property)
+                }
+
+                unboundCyclesInTypeParametersSupertypes(property)
+
+                property
             }
-
-            if (property.returnTypeRef is FirResolvedTypeRef && property.delegate != null) {
-                setAccessorTypesByPropertyType(property)
-            }
-
-            unboundCyclesInTypeParametersSupertypes(property)
-
-            property
         }
     }
 
@@ -147,9 +171,11 @@
     }
 
     override fun transformField(field: FirField, data: Any?): FirField {
-        return withScopeCleanup {
-            field.transformReturnTypeRef(this, data).transformAnnotations(this, data)
-            field
+        return withOwningSymbol(field.symbol) {
+            withScopeCleanup {
+                field.transformReturnTypeRef(this, data).transformAnnotations(this, data)
+                field
+            }
         }
     }
 
@@ -162,6 +188,12 @@
         } as FirSimpleFunction
     }
 
+    override fun transformDeclaration(declaration: FirDeclaration, data: Any?): FirDeclaration {
+        return withOwningSymbol(declaration.symbol) {
+            super.transformDeclaration(declaration, data)
+        }
+    }
+
     private fun unboundCyclesInTypeParametersSupertypes(typeParametersOwner: FirTypeParameterRefsOwner) {
         for (typeParameter in typeParametersOwner.typeParameters) {
             if (typeParameter !is FirTypeParameter) continue
@@ -197,18 +229,29 @@
 
     override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef {
         return typeResolverTransformer.withFile(currentFile) {
+            if (owningSymbol == null) {
+                val hasAnnotationsWithUnresolvedArguments = typeRef.annotations.filterIsInstance<FirAnnotationCall>()
+                    .any { it.argumentList !is FirResolvedArgumentList }
+
+                if (hasAnnotationsWithUnresolvedArguments) {
+                    error("$typeRef has annotations with unresolved arguments mapping, but no symbol responsible for their resolution")
+                }
+            }
+
             typeRef.transform(
                 typeResolverTransformer,
-                ScopeClassDeclaration(towerScope, classDeclarationsStack)
+                ScopeClassDeclaration(towerScope, classDeclarationsStack, owningSymbol)
             )
         }
     }
 
     override fun transformValueParameter(valueParameter: FirValueParameter, data: Any?): FirStatement {
-        valueParameter.transformReturnTypeRef(this, data)
-        valueParameter.transformAnnotations(this, data)
-        valueParameter.transformVarargTypeToArrayType()
-        return valueParameter
+        withOwningSymbol(valueParameter.symbol) {
+            valueParameter.transformReturnTypeRef(this, data)
+            valueParameter.transformAnnotations(this, data)
+            valueParameter.transformVarargTypeToArrayType()
+            return valueParameter
+        }
     }
 
     override fun transformBlock(block: FirBlock, data: Any?): FirStatement {
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt
index e1e557d..6d76c7c 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt
@@ -7,9 +7,11 @@
 
 import org.jetbrains.kotlin.fir.declarations.FirDeclaration
 import org.jetbrains.kotlin.fir.scopes.FirScope
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 
 data class ScopeClassDeclaration(
     val scopes: List<FirScope>,
     val containingDeclarations: List<FirDeclaration>,
-    val topContainer: FirDeclaration? = null
+    val owningSymbol: FirBasedSymbol<*>?,
+    val topContainer: FirDeclaration? = null,
 )
\ No newline at end of file
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt
index fd6b096..cea1eb9 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt
@@ -70,6 +70,7 @@
                     ScopeClassDeclaration(
                         components.createCurrentScopeList(),
                         context.containingClassDeclarations,
+                        (context.containers.lastOrNull() ?: context.file).symbol,
                         context.containers.lastOrNull { it is FirTypeParameterRefsOwner && it !is FirAnonymousFunction }
                     )
                 )
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt
index 67fbcd9..4c531eb 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt
@@ -200,9 +200,10 @@
         val name = annotationTypeRef.qualifier.last().name
         if (name !in REQUIRED_ANNOTATION_NAMES && acceptableFqNames.none { it.shortName() == name }) return annotation
 
+        val owner = classDeclarationsStack.lastOrNull() ?: argumentsTransformer.context.file
         val transformedAnnotation = annotation.transformAnnotationTypeRef(
             typeResolverTransformer,
-            ScopeClassDeclaration(scopes.asReversed(), classDeclarationsStack)
+            ScopeClassDeclaration(scopes.asReversed(), classDeclarationsStack, owner.symbol)
         )
         // TODO: what if we have type alias here?
         if (transformedAnnotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == Deprecated) {
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt
index 36f79c8..7b665e4 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt
@@ -7,16 +7,20 @@
 
 import org.jetbrains.kotlin.fir.expressions.FirAnnotation
 import org.jetbrains.kotlin.fir.render
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import kotlin.reflect.KClass
 
-class CustomAnnotationTypeAttribute(val annotations: List<FirAnnotation>) : ConeAttribute<CustomAnnotationTypeAttribute>() {
+class CustomAnnotationTypeAttribute(
+    val annotations: List<FirAnnotation>,
+    val owningSymbol: FirBasedSymbol<*>?,
+) : ConeAttribute<CustomAnnotationTypeAttribute>() {
     override fun union(other: CustomAnnotationTypeAttribute?): CustomAnnotationTypeAttribute? = null
 
     override fun intersect(other: CustomAnnotationTypeAttribute?): CustomAnnotationTypeAttribute? = null
 
     override fun add(other: CustomAnnotationTypeAttribute?): CustomAnnotationTypeAttribute {
         if (other == null || other === this) return this
-        return CustomAnnotationTypeAttribute(annotations + other.annotations)
+        return CustomAnnotationTypeAttribute(annotations + other.annotations, owningSymbol)
     }
 
     override fun isSubtypeOf(other: CustomAnnotationTypeAttribute?): Boolean = true
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt
index fdb235d..ca648e0 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt
@@ -11,6 +11,7 @@
 import org.jetbrains.kotlin.fir.extensions.extensionService
 import org.jetbrains.kotlin.fir.extensions.typeAttributeExtensions
 import org.jetbrains.kotlin.fir.render
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
 import org.jetbrains.kotlin.name.ClassId
 import org.jetbrains.kotlin.name.StandardClassIds
@@ -112,7 +113,11 @@
     else -> null
 }
 
-fun List<FirAnnotation>.computeTypeAttributes(session: FirSession, predefined: List<ConeAttribute<*>> = emptyList()): ConeAttributes {
+fun List<FirAnnotation>.computeTypeAttributes(
+    session: FirSession,
+    predefined: List<ConeAttribute<*>> = emptyList(),
+    owningSymbol: FirBasedSymbol<*>?,
+): ConeAttributes {
     if (this.isEmpty()) {
         if (predefined.isEmpty()) return ConeAttributes.Empty
         return ConeAttributes.create(predefined)
@@ -145,7 +150,7 @@
         }
     }
     if (customAnnotations.isNotEmpty()) {
-        attributes += CustomAnnotationTypeAttribute(customAnnotations)
+        attributes += CustomAnnotationTypeAttribute(customAnnotations, owningSymbol)
     }
     return ConeAttributes.create(attributes)
 }