[LL FIR] LLFirTargetResolver: introduce resolveDependencyTarget step

This entry point is required to be able to pre-resolve dependency
declarations.
E.g., fake override declaration shares annotation instances between
the original and the fake one, so we should resolve the original
firstly to avoid concurrent modification and correct context.
This will be done later.

This commit effectively only drops body resolution for a file annotation
container if the target element is not a file because this
is not required for correct resolution

^KT-63042
This commit is contained in:
Dmitrii Gridin
2023-11-20 16:23:55 +01:00
committed by Space Team
parent 0b07b86ec9
commit bc1e9fd2ea
7 changed files with 44 additions and 27 deletions
@@ -16,11 +16,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.LLFirDecla
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDelegatedConstructorIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.* import org.jetbrains.kotlin.analysis.low.level.api.fir.util.*
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDelegatedConstructorIsResolved
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
import org.jetbrains.kotlin.fir.FirElementWithResolveState import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
@@ -40,19 +37,22 @@ import org.jetbrains.kotlin.fir.references.builder.buildExplicitThisReference
import org.jetbrains.kotlin.fir.resolve.FirCodeFragmentContext import org.jetbrains.kotlin.fir.resolve.FirCodeFragmentContext
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
import org.jetbrains.kotlin.fir.resolve.codeFragmentContext import org.jetbrains.kotlin.fir.resolve.codeFragmentContext
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
import org.jetbrains.kotlin.fir.resolve.dfa.RealVariable import org.jetbrains.kotlin.fir.resolve.dfa.RealVariable
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForClass
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForFile
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractsDslNames import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractsDslNames
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForClass
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForFile
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.isResolved import org.jetbrains.kotlin.fir.types.isResolved
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
import org.jetbrains.kotlin.utils.findIsInstanceAnd import org.jetbrains.kotlin.utils.findIsInstanceAnd
@@ -107,6 +107,11 @@ private class LLFirBodyTargetResolver(
override val buildCfgForFiles: Boolean get() = false override val buildCfgForFiles: Boolean get() = false
} }
/**
* No one should depend on body resolution of another declaration
*/
override val skipDependencyTargetResolutionStep: Boolean get() = true
override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean { override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
when (target) { when (target) {
is FirRegularClass -> { is FirRegularClass -> {
@@ -123,7 +128,7 @@ private class LLFirBodyTargetResolver(
is FirFile -> { is FirFile -> {
if (target.resolvePhase >= resolverPhase) return true if (target.resolvePhase >= resolverPhase) return true
resolveFileAnnotationContainerIfNeeded(target) target.annotationsContainer?.lazyResolveToPhase(resolverPhase)
// resolve file CFG graph here, to do this we need to have property blocks resoled // resolve file CFG graph here, to do this we need to have property blocks resoled
resolveMembersForControlFlowGraph(target) resolveMembersForControlFlowGraph(target)
@@ -143,7 +148,7 @@ private class LLFirBodyTargetResolver(
} }
} }
return super.doResolveWithoutLock(target) return false
} }
private fun calculateControlFlowGraph(target: FirRegularClass) { private fun calculateControlFlowGraph(target: FirRegularClass) {
@@ -13,14 +13,16 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockPro
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDeprecationProviderIsResolved import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDeprecationProviderIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.forEachDependentDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isScriptDependentDeclaration
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
import org.jetbrains.kotlin.fir.FirAnnotationContainer import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElementWithResolveState import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.util.PrivateForInline
import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.annotationPlatformSupport
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCallCopy import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCallCopy
@@ -31,9 +33,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirCompilerRequiredA
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.FirUserTypeRef import org.jetbrains.kotlin.fir.types.FirUserTypeRef
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.forEachDependentDeclaration import org.jetbrains.kotlin.util.PrivateForInline
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isScriptDependentDeclaration
import org.jetbrains.kotlin.fir.declarations.annotationPlatformSupport
internal object LLFirCompilerAnnotationsLazyResolver : LLFirLazyResolver(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) { internal object LLFirCompilerAnnotationsLazyResolver : LLFirLazyResolver(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) {
override fun resolve( override fun resolve(
@@ -103,12 +103,8 @@ private class LLFirCompilerRequiredAnnotationsTargetResolver(
} }
override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean { override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
if (target is FirFile) {
resolveFileAnnotationContainerIfNeeded(target)
return false
}
when (target) { when (target) {
is FirFile -> return false
is FirRegularClass, is FirScript, is FirCodeFragment -> {} is FirRegularClass, is FirScript, is FirCodeFragment -> {}
else -> { else -> {
if (!target.isRegularDeclarationWithAnnotation) { if (!target.isRegularDeclarationWithAnnotation) {
@@ -148,7 +148,7 @@ private class LLFirStatusTargetResolver(
true true
} }
else -> super.doResolveWithoutLock(target) else -> false
} }
private inline fun <T : FirCallableDeclaration> performResolveWithOverriddenCallables( private inline fun <T : FirCallableDeclaration> performResolveWithOverriddenCallables(
@@ -120,7 +120,6 @@ private class LLFirSuperTypeTargetResolver(
superTypeUpdater = { target.replaceExpandedTypeRef(it.single()) }, superTypeUpdater = { target.replaceExpandedTypeRef(it.single()) },
) )
else -> { else -> {
resolveFileAnnotationContainerIfNeeded(target)
performCustomResolveUnderLock(target) { performCustomResolveUnderLock(target) {
// just update the phase // just update the phase
} }
@@ -27,7 +27,7 @@ internal abstract class LLFirTargetResolver(
/** /**
* Must be executed without a lock * Must be executed without a lock
*/ */
protected fun resolveFileAnnotationContainerIfNeeded(elementWithResolveState: FirElementWithResolveState) { private fun resolveFileAnnotationContainerIfNeeded(elementWithResolveState: FirElementWithResolveState) {
if (elementWithResolveState !is FirFile) return if (elementWithResolveState !is FirFile) return
val annotationContainer = elementWithResolveState.annotationsContainer ?: return val annotationContainer = elementWithResolveState.annotationsContainer ?: return
withFile(elementWithResolveState) { withFile(elementWithResolveState) {
@@ -35,6 +35,23 @@ internal abstract class LLFirTargetResolver(
} }
} }
/**
* @see resolveDependencyTarget
*/
open val skipDependencyTargetResolutionStep: Boolean get() = false
/**
* Requests the resolution for dependency targets to avoid race in the case of FIR instance sharing.
* Will be executed before resolution without a lock.
*
* @see skipDependencyTargetResolutionStep
*/
private fun resolveDependencyTarget(target: FirElementWithResolveState) {
if (skipDependencyTargetResolutionStep) return
resolveFileAnnotationContainerIfNeeded(target)
}
override fun withFile(firFile: FirFile, action: () -> Unit) { override fun withFile(firFile: FirFile, action: () -> Unit) {
action() action()
} }
@@ -57,10 +74,7 @@ internal abstract class LLFirTargetResolver(
protected open fun checkResolveConsistency() {} protected open fun checkResolveConsistency() {}
protected open fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean { protected open fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean = false
resolveFileAnnotationContainerIfNeeded(target)
return false
}
protected abstract fun doLazyResolveUnderLock(target: FirElementWithResolveState) protected abstract fun doLazyResolveUnderLock(target: FirElementWithResolveState)
@@ -74,6 +88,8 @@ internal abstract class LLFirTargetResolver(
} }
protected fun performResolve(target: FirElementWithResolveState) { protected fun performResolve(target: FirElementWithResolveState) {
resolveDependencyTarget(target)
if (doResolveWithoutLock(target)) return if (doResolveWithoutLock(target)) return
performCustomResolveUnderLock(target) { performCustomResolveUnderLock(target) {
doLazyResolveUnderLock(target) doLazyResolveUnderLock(target)
@@ -70,7 +70,7 @@ FILE: [ResolvedTo(IMPORTS)] annotations.kt
BODY_RESOLVE: BODY_RESOLVE:
FILE: [ResolvedTo(IMPORTS)] annotations.kt FILE: [ResolvedTo(IMPORTS)] annotations.kt
@FILE:R|kotlin/Suppress|[Types](names = vararg(String(1))) @FILE:R|kotlin/Suppress|[Types](names = vararg(String(1)))
[ResolvedTo(BODY_RESOLVE)] annotations container [ResolvedTo(ANNOTATION_ARGUMENTS)] annotations container
@R|kotlin/Suppress|[Types](names = vararg(String(2))) public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| { @R|kotlin/Suppress|[Types](names = vararg(String(2))) public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| {
} }
@@ -125,7 +125,7 @@ FILE: [ResolvedTo(IMPORTS)] annotationsScript.kts
BODY_RESOLVE: BODY_RESOLVE:
FILE: [ResolvedTo(IMPORTS)] annotationsScript.kts FILE: [ResolvedTo(IMPORTS)] annotationsScript.kts
@FILE:R|kotlin/Suppress|[Types](names = vararg(String(1))) @FILE:R|kotlin/Suppress|[Types](names = vararg(String(1)))
[ResolvedTo(BODY_RESOLVE)] annotations container [ResolvedTo(ANNOTATION_ARGUMENTS)] annotations container
context(<script>@R|kotlin/script/templates/standard/ScriptTemplateWithArgs|) context(<script>@R|kotlin/script/templates/standard/ScriptTemplateWithArgs|)
SCRIPT: [ResolvedTo(TYPES)] <script-annotationsScript.kts> SCRIPT: [ResolvedTo(TYPES)] <script-annotationsScript.kts>
[ResolvedTo(RAW_FIR)] lval args: R|kotlin/Array<kotlin/String>| [ResolvedTo(RAW_FIR)] lval args: R|kotlin/Array<kotlin/String>|
@@ -144,3 +144,4 @@ FILE: [ResolvedTo(BODY_RESOLVE)] annotationsScript.kts
@R|kotlin/Suppress|[Types](names = vararg(String(2))) public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| { @R|kotlin/Suppress|[Types](names = vararg(String(2))) public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| {
} }