From 31b36ee766ae60783e042e43a296bf3d63117c61 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Mon, 11 Sep 2023 20:13:40 +0200 Subject: [PATCH] [LL FIR] introduce lazyResolveRecursively API FirFile after KT-56683 has its own phases and resolution logic, so we should have a separate API for lazy resolution for FirFile and for the entire file ^KT-61296 Fixed --- .../fir/components/KtFirCompilerFacility.kt | 5 +- .../fir/components/KtFirImportOptimizer.kt | 7 +-- .../api/fir/LLFirLazyDeclarationResolver.kt | 12 ++++ .../api/targets/LLFirSingleResolveTarget.kt | 2 + .../fir/element/builder/FirElementBuilder.kt | 3 +- .../LLFirModuleLazyDeclarationResolver.kt | 56 ++++++++++--------- .../LLFirResolveMultiDesignationCollector.kt | 19 +++++-- .../testdata/lazyResolve/fileElements.txt | 2 +- .../AbstractFirLazyDeclarationResolveTest.kt | 6 +- ...stractFirLazyDeclarationResolveTestCase.kt | 4 +- ...sInheritorsCaclulatorPreAnalysisHandler.kt | 6 +- .../AbstractInBlockModificationTest.kt | 6 +- ...FirDummyCompilerLazyDeclarationResolver.kt | 1 + .../fir/symbols/FirLazyDeclarationResolver.kt | 41 +++++++++++++- .../simple.kt | 1 - ...azyDeclarationResolverWithPhaseChecking.kt | 4 ++ 16 files changed, 120 insertions(+), 55 deletions(-) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt index e13c555b337..f59794b3ce5 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt @@ -18,8 +18,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilt import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirWholeElementResolveTarget -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.resolve import org.jetbrains.kotlin.analysis.low.level.api.fir.compile.CodeFragmentCapturedId import org.jetbrains.kotlin.analysis.low.level.api.fir.compile.CodeFragmentCapturedValueAnalyzer import org.jetbrains.kotlin.analysis.low.level.api.fir.compile.CompilationPeerCollector @@ -51,6 +49,7 @@ import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirThisReference import org.jetbrains.kotlin.fir.references.toResolvedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.PsiIrFileEntry @@ -291,7 +290,7 @@ internal class KtFirCompilerFacility( private fun getFullyResolvedFirFile(file: KtFile): FirFile { val firFile = file.getOrBuildFirFile(firResolveSession) - LLFirWholeElementResolveTarget(firFile).resolve(FirResolvePhase.BODY_RESOLVE) + firFile.lazyResolveToPhaseRecursively(FirResolvePhase.BODY_RESOLVE) return firFile } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt index d192e829e9e..2dc703f2cd4 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.psi @@ -30,9 +29,9 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedSymbolError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedTypeQualifierError -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively import org.jetbrains.kotlin.fir.types.FirErrorTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.classId @@ -59,7 +58,7 @@ internal class KtFirImportOptimizer( val existingImports = file.importDirectives if (existingImports.isEmpty()) return KtImportOptimizerResult() - val firFile = file.getOrBuildFirFile(firResolveSession).apply { lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) } + val firFile = file.getOrBuildFirFile(firResolveSession).apply { lazyResolveToPhaseRecursively(FirResolvePhase.BODY_RESOLVE) } val explicitlyImportedFqNames = existingImports .asSequence() diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt index 82f539fc716..10704330e1a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt @@ -41,4 +41,16 @@ internal class LLFirLazyDeclarationResolver : FirLazyDeclarationResolver() { toPhase = toPhase, ) } + + override fun lazyResolveToPhaseRecursively(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) { + val fir = symbol.fir + val session = fir.moduleData.session + if (session !is LLFirResolvableModuleSession) return + val moduleComponents = session.moduleComponents + moduleComponents.firModuleLazyDeclarationResolver.lazyResolveRecursively( + target = fir, + scopeSession = moduleComponents.scopeSessionProvider.getScopeSession(), + toPhase = toPhase, + ) + } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirSingleResolveTarget.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirSingleResolveTarget.kt index cbfb2dcb3f6..b13d01f6b4f 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirSingleResolveTarget.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirSingleResolveTarget.kt @@ -16,6 +16,8 @@ class LLFirSingleResolveTarget( containerClasses: List, target: FirElementWithResolveState, ) : LLFirResolveTarget(firFile, containerClasses, target) { + constructor(firFile: FirFile) : this(firFile, emptyList(), firFile) + override fun visitTargetElement( element: FirElementWithResolveState, visitor: LLFirResolveTargetVisitor, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt index 34cd449b119..48f19710856 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf @@ -85,7 +86,7 @@ internal class FirElementBuilder( private fun getOrBuildFirForKtFile(ktFile: KtFile): FirFile { val firFile = moduleComponents.firFileBuilder.buildRawFirFileWithCaching(ktFile) - firFile.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) + firFile.lazyResolveToPhaseRecursively(FirResolvePhase.BODY_RESOLVE) return firFile } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirModuleLazyDeclarationResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirModuleLazyDeclarationResolver.kt index 81276f9233c..ffa0488ace5 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirModuleLazyDeclarationResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirModuleLazyDeclarationResolver.kt @@ -31,7 +31,7 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod * * Might resolve additional required declarations. * - * Resolution is performed under the lock specific to each declaration which is going to be resolved. + * Resolution is performed under the lock specific to each declaration that is going to be resolved. * * Suitable for body resolve or/and on-air resolve. */ @@ -40,28 +40,8 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod scopeSession: ScopeSession, toPhase: FirResolvePhase, ) { - val fromPhase = target.resolvePhase - - /** - * Currently [lazyResolve] on file means [LLFirWholeElementResolveTarget], but also [FirFile] itself - * has [resolvePhase] which does not match with the entire file resolution state. - * This additional [FirFile] condition can be dropped after KT-61296 - */ - if (target !is FirFile && fromPhase >= toPhase) return - - try { - resolveContainingFileToImports(target) - if (toPhase == FirResolvePhase.IMPORTS) return - - lazyResolveTargets( - targets = LLFirResolveMultiDesignationCollector.getDesignationsToResolve(target), - scopeSession = scopeSession, - toPhase = toPhase, - towerDataContextCollector = null, - ) - } catch (e: Exception) { - handleExceptionFromResolve(e, target, fromPhase, toPhase) - } + if (target.resolvePhase >= toPhase) return + lazyResolve(target, scopeSession, toPhase, LLFirResolveMultiDesignationCollector::getDesignationsToResolve) } /** @@ -69,7 +49,7 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod * * Might resolve additional required declarations. * - * Resolution is performed under the lock specific to each declaration which is going to be resolved. + * Resolution is performed under the lock specific to each declaration that is going to be resolved. * * Suitable for body resolve or/and on-air resolve. */ @@ -77,6 +57,32 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod target: FirRegularClass, scopeSession: ScopeSession, toPhase: FirResolvePhase, + ) { + lazyResolve(target, scopeSession, toPhase, LLFirResolveMultiDesignationCollector::getDesignationsToResolveWithCallableMembers) + } + + /** + * Lazily resolves the [target] with nested declarations to a given [toPhase] recursively. + * + * Might resolve additional required declarations. + * + * Resolution is performed under the lock specific to each declaration that is going to be resolved. + * + * Suitable for body resolve or/and on-air resolve. + */ + fun lazyResolveRecursively( + target: FirElementWithResolveState, + scopeSession: ScopeSession, + toPhase: FirResolvePhase, + ) { + lazyResolve(target, scopeSession, toPhase, LLFirResolveMultiDesignationCollector::getDesignationsToResolveRecursively) + } + + private inline fun lazyResolve( + target: T, + scopeSession: ScopeSession, + toPhase: FirResolvePhase, + resolveTargets: (T) -> List, ) { val fromPhase = target.resolvePhase try { @@ -84,7 +90,7 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod if (toPhase == FirResolvePhase.IMPORTS) return lazyResolveTargets( - targets = LLFirResolveMultiDesignationCollector.getDesignationsToResolveWithCallableMembers(target), + targets = resolveTargets(target), scopeSession = scopeSession, toPhase = toPhase, towerDataContextCollector = null, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirResolveMultiDesignationCollector.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirResolveMultiDesignationCollector.kt index 2e514157631..d6a05e350eb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirResolveMultiDesignationCollector.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirResolveMultiDesignationCollector.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithAllCallablesResolveTarget import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirSingleResolveTarget import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirWholeElementResolveTarget import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError @@ -19,12 +20,10 @@ import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor internal object LLFirResolveMultiDesignationCollector { - fun getDesignationsToResolve(target: FirElementWithResolveState): List { - return when (target) { - is FirFile -> listOf(LLFirWholeElementResolveTarget(target)) - else -> getMainDesignationToResolve(target)?.withAnnotationContainer() - } ?: emptyList() - } + fun getDesignationsToResolve(target: FirElementWithResolveState): List = when (target) { + is FirFile -> listOf(LLFirSingleResolveTarget(target)) + else -> getMainDesignationToResolve(target)?.withAnnotationContainer() + } ?: emptyList() fun getDesignationsToResolveWithCallableMembers(target: FirRegularClass): List { val designation = target.tryCollectDesignationWithFile() ?: return emptyList() @@ -32,6 +31,14 @@ internal object LLFirResolveMultiDesignationCollector { return resolveTarget.withAnnotationContainer() } + fun getDesignationsToResolveRecursively(target: FirElementWithResolveState): List { + if (target is FirFile) return listOf(LLFirWholeElementResolveTarget(target)) + + val designation = target.tryCollectDesignationWithFile() ?: return emptyList() + val resolveTarget = LLFirWholeElementResolveTarget(designation.firFile, designation.path, target) + return resolveTarget.withAnnotationContainer() + } + private fun LLFirResolveTarget.withAnnotationContainer(): List { val annotationsContainer = firFile.annotationsContainer if (annotationsContainer?.shouldBeResolved() != true) return listOf(this) diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/fileElements.txt b/analysis/low-level-api-fir/testdata/lazyResolve/fileElements.txt index fc7778beb54..36846e37e9e 100644 --- a/analysis/low-level-api-fir/testdata/lazyResolve/fileElements.txt +++ b/analysis/low-level-api-fir/testdata/lazyResolve/fileElements.txt @@ -1,5 +1,5 @@ RAW_FIR: -FILE: [ResolvedTo(IMPORTS)] fileElements.kt +FILE: [ResolvedTo(RAW_FIR)] fileElements.kt @FILE:Deprecated[Unresolved](LAZY_EXPRESSION) @FILE:Anno[Unresolved](LAZY_EXPRESSION) [ResolvedTo(RAW_FIR)] annotations container diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTest.kt index 0875559a8ad..1ad087e07a1 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTest.kt @@ -51,11 +51,7 @@ abstract class AbstractFirLazyDeclarationResolveTest : AbstractFirLazyDeclaratio val session = firResolveSession.useSiteFirSession as LLFirResolvableModuleSession val file = session.moduleComponents.firFileBuilder.buildRawFirFileWithCaching(ktFile) file to fun(phase: FirResolvePhase) { - session.moduleComponents.firModuleLazyDeclarationResolver.lazyResolveTarget( - LLFirSingleResolveTarget(file, emptyList(), file), - phase, - towerDataContextCollector = null, - ) + file.lazyResolveToPhase(phase) } } else -> { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTestCase.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTestCase.kt index 5ad149c3c00..68b2ddd200c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTestCase.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyDeclarationResolveTestCase.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer @@ -83,7 +83,7 @@ abstract class AbstractFirLazyDeclarationResolveTestCase : AbstractLowLevelApiSi resolveWithClearCaches(ktFile) { llSession -> checkSession(llSession) val firFile = llSession.getOrBuildFirFile(ktFile) - firFile.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) + firFile.lazyResolveToPhaseRecursively(FirResolvePhase.BODY_RESOLVE) if (resultBuilder.isNotEmpty()) { resultBuilder.appendLine() } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt index c3d7f7da3c5..dca574a9bad 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.transformers.FirSealedClassInheritorsProcessor -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability @@ -64,7 +64,7 @@ class SealedClassesInheritorsCaclulatorPreAnalysisHandler( firFiles: List, tmpFirResolveSession: LLFirResolveSession ): Map> { - firFiles.forEach { it.lazyResolveToPhase(FirResolvePhase.TYPES) } + firFiles.forEach { it.lazyResolveToPhaseRecursively(FirResolvePhase.TYPES) } val inheritorsCollector = FirSealedClassInheritorsProcessor.InheritorsCollector(tmpFirResolveSession.useSiteFirSession) val sealedClassInheritorsMap = mutableMapOf>() firFiles.forEach { it.accept(inheritorsCollector, sealedClassInheritorsMap) } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractInBlockModificationTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractInBlockModificationTest.kt index 7feac43a4a6..58e62566276 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractInBlockModificationTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractInBlockModificationTest.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerPro import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor import org.jetbrains.kotlin.fir.declarations.FirResolvePhase -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf @@ -70,7 +70,7 @@ internal fun testInBlockModification( val declaration = elementToModify.getNonLocalContainingOrThisDeclaration() ?: file val firDeclarationBefore = declaration.getOrBuildFirOfType(firSession) val declarationToRender = if (dumpFirFile) { - file.getOrBuildFirFile(firSession).also { it.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) } + file.getOrBuildFirFile(firSession).also { it.lazyResolveToPhaseRecursively(FirResolvePhase.BODY_RESOLVE) } } else { firDeclarationBefore } @@ -100,7 +100,7 @@ internal fun testInBlockModification( val textAfter = if (dumpFirFile) { // we should resolve the entire file instead of the declaration to be sure that this declaration will be // resolved by file resolution as well - declarationToRender.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) + declarationToRender.lazyResolveToPhaseRecursively(FirResolvePhase.BODY_RESOLVE) declarationToRender.render() } else { declaration.getOrBuildFirOfType(firSession) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirDummyCompilerLazyDeclarationResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirDummyCompilerLazyDeclarationResolver.kt index 76aff0cfa80..f7cafd27f0a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirDummyCompilerLazyDeclarationResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirDummyCompilerLazyDeclarationResolver.kt @@ -16,4 +16,5 @@ object FirDummyCompilerLazyDeclarationResolver : FirLazyDeclarationResolver() { override fun lazyResolveToPhase(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) {} override fun lazyResolveToPhaseWithCallableMembers(symbol: FirClassSymbol<*>, toPhase: FirResolvePhase) {} + override fun lazyResolveToPhaseRecursively(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) {} } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt index 7a6e1e62c00..1ba2ae7b0f9 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt @@ -40,8 +40,20 @@ abstract class FirLazyDeclarationResolver : FirSessionComponent { } } + /** + * @see org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase + */ abstract fun lazyResolveToPhase(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) + + /** + * @see org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseWithCallableMembers + */ abstract fun lazyResolveToPhaseWithCallableMembers(symbol: FirClassSymbol<*>, toPhase: FirResolvePhase) + + /** + * @see org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively + */ + abstract fun lazyResolveToPhaseRecursively(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) } class FirLazyResolveContractViolationException( @@ -104,7 +116,6 @@ fun FirDeclaration.lazyResolveToPhase(toPhase: FirResolvePhase) { * * @see lazyResolveToPhase */ - fun FirClassSymbol<*>.lazyResolveToPhaseWithCallableMembers(toPhase: FirResolvePhase) { fir.lazyDeclarationResolver.lazyResolveToPhaseWithCallableMembers(this, toPhase) } @@ -117,3 +128,31 @@ fun FirClassSymbol<*>.lazyResolveToPhaseWithCallableMembers(toPhase: FirResolveP fun FirClass.lazyResolveToPhaseWithCallableMembers(toPhase: FirResolvePhase) { symbol.lazyResolveToPhaseWithCallableMembers(toPhase) } + +/** + * Lazy resolve [FirBasedSymbol] and all nested declarations to [FirResolvePhase]. + * + * In the case of lazy resolution (inside Analysis API), it checks that the declaration phase `>= toPhase`. + * If not, it resolves the declaration for the requested phase. + * + * If the [lazyResolveToPhase] is called inside a fir transformer, + * it should always request the phase which is strictly lower than the current transformer phase, + * otherwise a deadlock/StackOverflow is possible. + * + * For the compiler mode, it does nothing, as the compiler is non-lazy. + * + * @receiver [FirBasedSymbol] which should be resolved + * @param toPhase the minimum phase, the declaration and all nested declarations should be resolved to after an execution of the [lazyResolveToPhase] + */ +fun FirBasedSymbol<*>.lazyResolveToPhaseRecursively(toPhase: FirResolvePhase) { + fir.lazyDeclarationResolver.lazyResolveToPhaseRecursively(this, toPhase) +} + +/** + * Lazy resolve [FirDeclaration] and all nested declarations to [FirResolvePhase]. + * + * @see lazyResolveToPhaseRecursively + */ +fun FirDeclaration.lazyResolveToPhaseRecursively(toPhase: FirResolvePhase) { + symbol.lazyResolveToPhaseRecursively(toPhase) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt index 4d480109025..5b9ca598247 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt @@ -1,5 +1,4 @@ // IGNORE_REVERSED_RESOLVE -// IGNORE_CONTRACT_VIOLATIONS // FIR_IDENTICAL @Retention(AnnotationRetention.SOURCE) @Repeatable diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt index ec4705b22b6..fde9066f1d9 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt @@ -28,6 +28,10 @@ class FirCompilerLazyDeclarationResolverWithPhaseChecking : FirLazyDeclarationRe checkIfCanLazyResolveToPhase(toPhase) } + override fun lazyResolveToPhaseRecursively(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) { + checkIfCanLazyResolveToPhase(toPhase) + } + override fun startResolvingPhase(phase: FirResolvePhase) { check(currentTransformerPhase == null) currentTransformerPhase = phase