[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
This commit is contained in:
Dmitrii Gridin
2023-12-19 17:32:50 +01:00
committed by Space Team
parent 6ca6221be9
commit d83392a27a
4 changed files with 74 additions and 47 deletions
@@ -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<FirClassifierSymbol<*>> {
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,
)
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<T>|
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<T>|
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<kotlin/String>| {
@@ -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<FirClassifierSymbol<*>> {
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 -> {}
}
}