From d83392a27acee733d26a75881b1075fd24b46829 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Tue, 19 Dec 2023 17:32:50 +0100 Subject: [PATCH] [LL FIR] LLFirStatusLazyResolver: pass correct session during resolution We should use the declaration-site session to have stable resolution order. The same scheme is applicable during regular lazy resolution calls. Also, this means that we should process 'expect' classes before 'actual' like it was for 'super' and 'sub' classes ^KT-63547 --- .../transformers/LLFirStatusLazyResolver.kt | 23 +++++++++--- .../lazyResolve/functions/actualOverride.txt | 36 +++++++++---------- .../transitiveSubstitutionFakeOverride.txt | 36 +++++++++---------- .../FirStatusResolveTransformer.kt | 26 ++++++++++---- 4 files changed, 74 insertions(+), 47 deletions(-) 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 9b6d1325d05..b767e33ba33 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirSingleRe import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget import org.jetbrains.kotlin.analysis.low.level.api.fir.api.tryCollectDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDeclarationStatusIsResolved import org.jetbrains.kotlin.analysis.low.level.api.fir.util.forEachDependentDeclaration import org.jetbrains.kotlin.fir.FirElementWithResolveState @@ -21,7 +22,11 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.StatusComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector +import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.toSymbol import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.Name @@ -83,7 +88,7 @@ private fun LLFirResolveTarget.resolveMode(): StatusResolveMode = when (this) { else -> StatusResolveMode.AllCallables } -private class LLStatusComputationSession : StatusComputationSession() { +private class LLStatusComputationSession(val useSiteSession: FirSession) : StatusComputationSession() { private var shouldCheckForActualization: Boolean = false inline fun withClass(regularClass: FirClass, transformer: (FirClass) -> Unit) { @@ -107,7 +112,7 @@ private class LLFirStatusTargetResolver( lockProvider: LLFirLockProvider, session: FirSession, scopeSession: ScopeSession, - private val statusComputationSession: LLStatusComputationSession = LLStatusComputationSession(), + private val statusComputationSession: LLStatusComputationSession = LLStatusComputationSession(session), private val resolveMode: StatusResolveMode, ) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.STATUS, isJumpingPhase = false) { private val transformer = Transformer(session, scopeSession) @@ -236,6 +241,15 @@ private class LLFirStatusTargetResolver( return klass } + override fun superTypeToSymbols(typeRef: FirTypeRef): List> { + val type = typeRef.coneType + val originalClassifierSymbol = type.toSymbol(session) + val useSiteSymbol = type.toSymbol(computationSession.useSiteSession) + + // Resolve an 'expect' declaration before an 'actual' as it is like 'super' and 'sub' classes + return listOfNotNull(originalClassifierSymbol, useSiteSymbol?.takeIf { it != originalClassifierSymbol }) + } + override fun resolveClassForSuperType(regularClass: FirRegularClass): Boolean { // We cannot skip supertype resolution when there is a possibility // that some supertypes might need to be actualized in the current context @@ -248,11 +262,12 @@ private class LLFirStatusTargetResolver( } val target = regularClass.tryCollectDesignationWithFile()?.asResolveTarget() ?: return false + val targetSession = target.target.llFirSession val resolver = LLFirStatusTargetResolver( target, lockProvider, - session, - scopeSession, + targetSession, + targetSession.getScopeSession(), computationSession, resolveMode = resolveMode, ) diff --git a/analysis/low-level-api-fir/testData/lazyResolve/functions/actualOverride.txt b/analysis/low-level-api-fir/testData/lazyResolve/functions/actualOverride.txt index 2d00966f4cb..25e894d6a9e 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/functions/actualOverride.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/functions/actualOverride.txt @@ -270,10 +270,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt STATUS: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? open expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public open expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -315,10 +315,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt EXPECT_ACTUAL_MATCHING: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? open expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public open expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -360,10 +360,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt CONTRACTS: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? open expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public open expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -406,10 +406,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt IMPLICIT_TYPES_BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? open expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public open expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -452,10 +452,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt ANNOTATION_ARGUMENTS: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? open expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public open expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -498,10 +498,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? open expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public open expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { diff --git a/analysis/low-level-api-fir/testData/lazyResolve/functions/transitiveSubstitutionFakeOverride.txt b/analysis/low-level-api-fir/testData/lazyResolve/functions/transitiveSubstitutionFakeOverride.txt index 5b9f988d737..c2744900ec0 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/functions/transitiveSubstitutionFakeOverride.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/functions/transitiveSubstitutionFakeOverride.txt @@ -282,10 +282,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt STATUS: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? final? expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public final expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -329,10 +329,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt EXPECT_ACTUAL_MATCHING: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? final? expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public final expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -376,10 +376,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt CONTRACTS: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? final? expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public final expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -425,10 +425,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt IMPLICIT_TYPES_BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? final? expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public final expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -474,10 +474,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt ANNOTATION_ARGUMENTS: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? final? expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public final expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { @@ -523,10 +523,10 @@ FILE: [ResolvedTo(IMPORTS)] jvm.kt BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] common.kt - public? open expect [ResolvedTo(SUPER_TYPES)] class Base<[ResolvedTo(SUPER_TYPES)] T> : R|kotlin/Any| { - public? expect [ResolvedTo(RAW_FIR)] [ContainingClassKey=Base] constructor<[ResolvedTo(SUPER_TYPES)] T>(): R|Base| + public open expect [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| { + public expect [ResolvedTo(STATUS)] [ContainingClassKey=Base] constructor<[ResolvedTo(STATUS)] T>(): R|Base| - public? final? expect [ResolvedTo(RAW_FIR)] fun existingMethodInBase([ResolvedTo(RAW_FIR)] param: T): R|kotlin/Unit| + public final expect [ResolvedTo(STATUS)] fun existingMethodInBase([ResolvedTo(STATUS)] param: R|T|): R|kotlin/Unit| } public open [ResolvedTo(STATUS)] class Transitive : R|Base| { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index 825c1e8af60..7a8d1bdb867 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -328,26 +328,38 @@ abstract class AbstractFirStatusResolveTransformer( fun forceResolveStatusesOfSupertypes(regularClass: FirClass) { for (superTypeRef in regularClass.superTypeRefs) { - forceResolveStatusOfCorrespondingClass(superTypeRef) + for (classifierSymbol in superTypeToSymbols(superTypeRef)) { + forceResolveStatusOfCorrespondingClass(classifierSymbol) + } } } - private fun forceResolveStatusOfCorrespondingClass(typeRef: FirTypeRef) { - val superClassSymbol = typeRef.coneType.toSymbol(session) + /** + * @return symbols which should be resolved to [FirResolvePhase.STATUS] phase + */ + protected open fun superTypeToSymbols(typeRef: FirTypeRef): List> { + return listOfNotNull(typeRef.coneType.toSymbol(session)) + } + + private fun forceResolveStatusOfCorrespondingClass(superClassSymbol: FirClassifierSymbol<*>) { if (isTransformerForLocalDeclarations) { if (superClassSymbol is FirClassSymbol) { superClassSymbol.lazyResolveToPhaseWithCallableMembers(FirResolvePhase.STATUS) } else { - superClassSymbol?.lazyResolveToPhase(FirResolvePhase.STATUS) + superClassSymbol.lazyResolveToPhase(FirResolvePhase.STATUS) } } else { - superClassSymbol?.lazyResolveToPhase(FirResolvePhase.STATUS.previous) + superClassSymbol.lazyResolveToPhase(FirResolvePhase.STATUS.previous) } when (superClassSymbol) { is FirRegularClassSymbol -> forceResolveStatusesOfClass(superClassSymbol.fir) - is FirTypeAliasSymbol -> forceResolveStatusOfCorrespondingClass(superClassSymbol.fir.expandedTypeRef) - is FirTypeParameterSymbol, is FirAnonymousObjectSymbol, null -> {} + is FirTypeAliasSymbol -> { + for (classifierSymbol in superTypeToSymbols(superClassSymbol.fir.expandedTypeRef)) { + forceResolveStatusOfCorrespondingClass(classifierSymbol) + } + } + is FirTypeParameterSymbol, is FirAnonymousObjectSymbol -> {} } }