[LL FIR] pass correct context during class annotation arguments mapping

The root cause of the problem is that we visit class annotations more
accurately than in the regular compiler transformer, so we have
a difference: the compiler assumes that annotation processing
of the class is called already inside this class, so it should enable
CLASS_HEADER_ANNOTATIONS mode to not capture extra context.
But we in LL FIR do this out of the class, so such context switching
is redundant and results in cutting out the outer class context

^KT-62587 Fixed
This commit is contained in:
Dmitrii Gridin
2023-10-16 19:46:20 +02:00
committed by Space Team
parent bbd09c6272
commit b03e3f0b0d
9 changed files with 45 additions and 77 deletions
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodie
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.util.PrivateForInline
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
@@ -20,6 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveCon
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirAnnotationArgumentsResolveTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.util.PrivateForInline
internal object LLFirAnnotationArgumentsLazyResolver : LLFirLazyResolver(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) {
override fun resolve(
@@ -154,9 +154,17 @@ private class LLFirAnnotationArgumentsTargetResolver(
internal fun LLFirAbstractBodyTargetResolver.transformAnnotations(target: FirElementWithResolveState) {
when {
target is FirRegularClass -> transformer.declarationsTransformer?.let { declarationsTransformer ->
target.transformAnnotations(declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformTypeParameters(declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformSuperTypeRefs(declarationsTransformer, ResolutionMode.ContextIndependent)
if (this is LLFirAnnotationArgumentsTargetResolver) {
target.transformAnnotations(declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformTypeParameters(declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformSuperTypeRefs(declarationsTransformer, ResolutionMode.ContextIndependent)
} else {
declarationsTransformer.context.insideClassHeader {
target.transformAnnotations(declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformTypeParameters(declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformSuperTypeRefs(declarationsTransformer, ResolutionMode.ContextIndependent)
}
}
}
target is FirScript -> {
@@ -404,10 +404,10 @@ FILE: [ResolvedTo(IMPORTS)] annotationWithConstantFromNestedClass.kt
LAZY_super<R|kotlin/Any|>
}
public final const [ResolvedTo(STATUS)] val CONSTANT_FROM_COMPANION: <implicit> = LAZY_EXPRESSION
public [ResolvedTo(STATUS)] [ContainingClassKey=Companion] get(): <implicit>
public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val CONSTANT_FROM_COMPANION: R|kotlin/Int| = Int(42)
public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] [ContainingClassKey=Companion] get(): R|kotlin/Int|
@R|Anno|[Types](number = <Unresolved name: CONSTANT_FROM_COMPANION>#) public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class Nested : R|kotlin/Any| {
@R|Anno|[Types](number = this@R|/Outer.Companion|.R|/Outer.Companion.CONSTANT_FROM_COMPANION|) public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class Nested : R|kotlin/Any| {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=Nested] constructor(): R|Outer.Companion.Nested| {
LAZY_super<R|kotlin/Any|>
}
@@ -439,10 +439,10 @@ FILE: [ResolvedTo(IMPORTS)] annotationWithConstantFromNestedClass.kt
LAZY_super<R|kotlin/Any|>
}
public final const [ResolvedTo(STATUS)] val CONSTANT_FROM_COMPANION: <implicit> = LAZY_EXPRESSION
public [ResolvedTo(STATUS)] [ContainingClassKey=Companion] get(): <implicit>
public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val CONSTANT_FROM_COMPANION: R|kotlin/Int| = Int(42)
public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] [ContainingClassKey=Companion] get(): R|kotlin/Int|
@R|Anno|[Types](number = <Unresolved name: CONSTANT_FROM_COMPANION>#) public final [ResolvedTo(BODY_RESOLVE)] class Nested : R|kotlin/Any| {
@R|Anno|[Types](number = this@R|/Outer.Companion|.R|/Outer.Companion.CONSTANT_FROM_COMPANION|) public final [ResolvedTo(BODY_RESOLVE)] class Nested : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Nested] constructor(): R|Outer.Companion.Nested| {
super<R|kotlin/Any|>()
}
@@ -477,7 +477,7 @@ FILE: [ResolvedTo(BODY_RESOLVE)] annotationWithConstantFromNestedClass.kt
public final const [ResolvedTo(BODY_RESOLVE)] val CONSTANT_FROM_COMPANION: R|kotlin/Int| = Int(42)
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Companion] get(): R|kotlin/Int|
@R|Anno|[Types](number = <Unresolved name: CONSTANT_FROM_COMPANION>#) public final [ResolvedTo(BODY_RESOLVE)] class Nested : R|kotlin/Any| {
@R|Anno|[Types](number = this@R|/Outer.Companion|.R|/Outer.Companion.CONSTANT_FROM_COMPANION|) public final [ResolvedTo(BODY_RESOLVE)] class Nested : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Nested] constructor(): R|Outer.Companion.Nested| {
super<R|kotlin/Any|>()
}
@@ -313,7 +313,7 @@ FILE: [ResolvedTo(IMPORTS)] nestedClassAsAnnotationArgument.kt
LAZY_super<R|kotlin/Any|>
}
@R|Special|[Types](why = <getClass>(<Unresolved name: Nested>#)) public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class Nested<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] T> : R|@R|Special|(why = <getClass>(<Unresolved name: Nested>#)) Interface| {
@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class Nested<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] T> : R|@R|Special|(why = <getClass>(Q|Outer.Nested|)) Interface| {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=Nested] constructor<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] T>(): R|Outer.Nested<T>| {
LAZY_super<<implicit>>
}
@@ -340,7 +340,7 @@ FILE: [ResolvedTo(IMPORTS)] nestedClassAsAnnotationArgument.kt
LAZY_super<R|kotlin/Any|>
}
@R|Special|[Types](why = <getClass>(<Unresolved name: Nested>#)) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = <getClass>(<Unresolved name: Nested>#)) Interface| {
@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = <getClass>(Q|Outer.Nested|)) Interface| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Nested] constructor<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(BODY_RESOLVE)] T>(): R|Outer.Nested<T>| {
super<R|kotlin/Any|>()
}
@@ -367,7 +367,7 @@ FILE: [ResolvedTo(BODY_RESOLVE)] nestedClassAsAnnotationArgument.kt
super<R|kotlin/Any|>()
}
@R|Special|[Types](why = <getClass>(<Unresolved name: Nested>#)) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = <getClass>(<Unresolved name: Nested>#)) Interface| {
@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = <getClass>(Q|Outer.Nested|)) Interface| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Nested] constructor<@R|Special|[Types](why = <getClass>(Q|Outer.Nested|)) [ResolvedTo(BODY_RESOLVE)] T>(): R|Outer.Nested<T>| {
super<R|kotlin/Any|>()
}
@@ -313,7 +313,7 @@ FILE: [ResolvedTo(IMPORTS)] nestedClassAsAnnotationArgument2.kt
LAZY_super<R|kotlin/Any|>
}
@R|Special|[Types](why = <Unresolved name: Nested>#) public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class Nested<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] T> : R|@R|Special|(why = <Unresolved name: Nested>#) Interface| {
@R|Special|[Types](why = Q|Outer.Nested|) public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class Nested<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] T> : R|@R|Special|(why = Q|Outer.Nested|) Interface| {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=Nested] constructor<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] T>(): R|Outer.Nested<T>| {
LAZY_super<<implicit>>
}
@@ -340,7 +340,7 @@ FILE: [ResolvedTo(IMPORTS)] nestedClassAsAnnotationArgument2.kt
LAZY_super<R|kotlin/Any|>
}
@R|Special|[Types](why = <Unresolved name: Nested>#) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = <Unresolved name: Nested>#) Interface| {
@R|Special|[Types](why = Q|Outer.Nested|) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = Q|Outer.Nested|) Interface| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Nested] constructor<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(BODY_RESOLVE)] T>(): R|Outer.Nested<T>| {
super<R|kotlin/Any|>()
}
@@ -367,7 +367,7 @@ FILE: [ResolvedTo(BODY_RESOLVE)] nestedClassAsAnnotationArgument2.kt
super<R|kotlin/Any|>()
}
@R|Special|[Types](why = <Unresolved name: Nested>#) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = <Unresolved name: Nested>#) Interface| {
@R|Special|[Types](why = Q|Outer.Nested|) public final [ResolvedTo(BODY_RESOLVE)] class Nested<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(BODY_RESOLVE)] T> : R|@R|Special|(why = Q|Outer.Nested|) Interface| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=Nested] constructor<@R|Special|[Types](why = Q|Outer.Nested|) [ResolvedTo(BODY_RESOLVE)] T>(): R|Outer.Nested<T>| {
super<R|kotlin/Any|>()
}
@@ -90,6 +90,24 @@ class BodyResolveContext(
@set:PrivateForInline
var inferenceSession: FirInferenceSession = FirInferenceSession.DEFAULT
/**
* This is required to avoid changing current mode into [FirTowerDataMode.CLASS_HEADER_ANNOTATIONS].
* E.g., we can visit the same annotation in two ways during a class visiting and outside of this class
*/
@set:PrivateForInline
var insideClassHeader: Boolean = false
@OptIn(PrivateForInline::class)
inline fun insideClassHeader(action: () -> Unit) {
val old = insideClassHeader
insideClassHeader = true
try {
action()
} finally {
insideClassHeader = old
}
}
/**
* CS for an outer type system if it's relevant, for example, in the case of `val x by myGenericDelegateCall()`,
* relevant `getValue` call is expected to be resolved in the context of an outer CS built from `myGenericDelegateCall()` and
@@ -751,8 +769,8 @@ class BodyResolveContext(
inline fun <T> forAnnotation(
f: () -> T
): T {
return when (containerIfAny) {
is FirRegularClass -> withTowerDataMode(FirTowerDataMode.CLASS_HEADER_ANNOTATIONS, f)
return when {
containerIfAny is FirRegularClass && !insideClassHeader -> withTowerDataMode(FirTowerDataMode.CLASS_HEADER_ANNOTATIONS, f)
else -> f()
}
}
@@ -1,14 +0,0 @@
// LL_FIR_DIVERGENCE
// KT-62587
// LL_FIR_DIVERGENCE
// FIR_IDENTICAL
annotation class Anno(val number: Int)
class Outer {
companion object {
const val CONSTANT_FROM_COMPANION = 42
@Anno(<!UNRESOLVED_REFERENCE!>CONSTANT_FROM_COMPANION<!>)
class Nested
}
}
@@ -1,15 +0,0 @@
// LL_FIR_DIVERGENCE
// KT-62587
// LL_FIR_DIVERGENCE
// FIR_IDENTICAL
import kotlin.reflect.KClass
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE)
annotation class Special(val why: KClass<*>)
interface Interface
class Outer {
@Special(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>Nested<!>::class<!>)
class Nested<@Special(Nested::class) T> : @Special(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>Nested<!>::class<!>) Interface
}
@@ -1,14 +0,0 @@
// LL_FIR_DIVERGENCE
// KT-62587
// LL_FIR_DIVERGENCE
import kotlin.reflect.KClass
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE)
annotation class Special(val why: KClass<*>)
interface Interface
class Outer {
@Special(<!UNRESOLVED_REFERENCE!>Nested<!>)
class Nested<@Special(<!ARGUMENT_TYPE_MISMATCH, NO_COMPANION_OBJECT!>Nested<!>) T> : @Special(<!UNRESOLVED_REFERENCE!>Nested<!>) Interface
}
@@ -1,15 +0,0 @@
// LL_FIR_DIVERGENCE
// KT-62587
// LL_FIR_DIVERGENCE
// FIR_IDENTICAL
import kotlin.reflect.KClass
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class Special(val why: KClass<*>)
interface Interface
object Outer {
@Special(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>Nested<!>::class<!>)
object Nested : @Special(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>Nested<!>::class<!>) Interface
}