[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.project.structure.llFirModuleData
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.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDelegatedConstructorIsResolved
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
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.ScopeSession
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.dfa.FirControlFlowGraphReferenceImpl
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.FirResolveContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractsDslNames
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.isResolved
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.psi.KtCodeFragment
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.withPsiEntry
import org.jetbrains.kotlin.utils.findIsInstanceAnd
@@ -107,6 +107,11 @@ private class LLFirBodyTargetResolver(
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 {
when (target) {
is FirRegularClass -> {
@@ -123,7 +128,7 @@ private class LLFirBodyTargetResolver(
is FirFile -> {
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
resolveMembersForControlFlowGraph(target)
@@ -143,7 +148,7 @@ private class LLFirBodyTargetResolver(
}
}
return super.doResolveWithoutLock(target)
return false
}
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.sessions.llFirSession
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.fir.FirAnnotationContainer
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.caches.firCachesFactory
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.FirAnnotationCall
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.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.FirUserTypeRef
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.fir.declarations.annotationPlatformSupport
import org.jetbrains.kotlin.util.PrivateForInline
internal object LLFirCompilerAnnotationsLazyResolver : LLFirLazyResolver(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) {
override fun resolve(
@@ -103,12 +103,8 @@ private class LLFirCompilerRequiredAnnotationsTargetResolver(
}
override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
if (target is FirFile) {
resolveFileAnnotationContainerIfNeeded(target)
return false
}
when (target) {
is FirFile -> return false
is FirRegularClass, is FirScript, is FirCodeFragment -> {}
else -> {
if (!target.isRegularDeclarationWithAnnotation) {
@@ -148,7 +148,7 @@ private class LLFirStatusTargetResolver(
true
}
else -> super.doResolveWithoutLock(target)
else -> false
}
private inline fun <T : FirCallableDeclaration> performResolveWithOverriddenCallables(
@@ -120,7 +120,6 @@ private class LLFirSuperTypeTargetResolver(
superTypeUpdater = { target.replaceExpandedTypeRef(it.single()) },
)
else -> {
resolveFileAnnotationContainerIfNeeded(target)
performCustomResolveUnderLock(target) {
// just update the phase
}
@@ -27,7 +27,7 @@ internal abstract class LLFirTargetResolver(
/**
* Must be executed without a lock
*/
protected fun resolveFileAnnotationContainerIfNeeded(elementWithResolveState: FirElementWithResolveState) {
private fun resolveFileAnnotationContainerIfNeeded(elementWithResolveState: FirElementWithResolveState) {
if (elementWithResolveState !is FirFile) return
val annotationContainer = elementWithResolveState.annotationsContainer ?: return
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) {
action()
}
@@ -57,10 +74,7 @@ internal abstract class LLFirTargetResolver(
protected open fun checkResolveConsistency() {}
protected open fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
resolveFileAnnotationContainerIfNeeded(target)
return false
}
protected open fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean = false
protected abstract fun doLazyResolveUnderLock(target: FirElementWithResolveState)
@@ -74,6 +88,8 @@ internal abstract class LLFirTargetResolver(
}
protected fun performResolve(target: FirElementWithResolveState) {
resolveDependencyTarget(target)
if (doResolveWithoutLock(target)) return
performCustomResolveUnderLock(target) {
doLazyResolveUnderLock(target)
@@ -70,7 +70,7 @@ FILE: [ResolvedTo(IMPORTS)] annotations.kt
BODY_RESOLVE:
FILE: [ResolvedTo(IMPORTS)] annotations.kt
@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| {
}
@@ -125,7 +125,7 @@ FILE: [ResolvedTo(IMPORTS)] annotationsScript.kts
BODY_RESOLVE:
FILE: [ResolvedTo(IMPORTS)] annotationsScript.kts
@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|)
SCRIPT: [ResolvedTo(TYPES)] <script-annotationsScript.kts>
[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| {
}