From bc1e9fd2ea7ae1c7b263db3370cee17a2d30018e Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Mon, 20 Nov 2023 16:23:55 +0100 Subject: [PATCH] [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 --- .../fir/transformers/LLFirBodyLazyResolver.kt | 23 +++++++++------- .../LLFirCompilerAnnotationsLazyResolver.kt | 14 ++++------ .../transformers/LLFirStatusLazyResolver.kt | 2 +- .../LLFirSupertypeLazyResolver.kt | 1 - .../fir/transformers/LLFirTargetResolver.kt | 26 +++++++++++++++---- .../testData/lazyResolve/annotations.txt | 2 +- .../lazyResolve/annotationsScript.txt | 3 ++- 7 files changed, 44 insertions(+), 27 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt index e83950257e3..f7c98dd9290 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt @@ -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) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirCompilerAnnotationsLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirCompilerAnnotationsLazyResolver.kt index 1503757ac4d..ba2a418ec42 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirCompilerAnnotationsLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirCompilerAnnotationsLazyResolver.kt @@ -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) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirStatusLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirStatusLazyResolver.kt index aae33a2677d..65fbe1b33a3 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirStatusLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirStatusLazyResolver.kt @@ -148,7 +148,7 @@ private class LLFirStatusTargetResolver( true } - else -> super.doResolveWithoutLock(target) + else -> false } private inline fun performResolveWithOverriddenCallables( diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt index ad24d314846..4c6bdafa00a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt @@ -120,7 +120,6 @@ private class LLFirSuperTypeTargetResolver( superTypeUpdater = { target.replaceExpandedTypeRef(it.single()) }, ) else -> { - resolveFileAnnotationContainerIfNeeded(target) performCustomResolveUnderLock(target) { // just update the phase } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt index 1f3473381ed..8037f25788e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt @@ -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) diff --git a/analysis/low-level-api-fir/testData/lazyResolve/annotations.txt b/analysis/low-level-api-fir/testData/lazyResolve/annotations.txt index 4b9547efba4..244a5d8fddf 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/annotations.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/annotations.txt @@ -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| { } diff --git a/analysis/low-level-api-fir/testData/lazyResolve/annotationsScript.txt b/analysis/low-level-api-fir/testData/lazyResolve/annotationsScript.txt index eda78025fb6..be83e37952e 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/annotationsScript.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/annotationsScript.txt @@ -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(