[FIR] Reuse expect/actual matching data of outer declarations during matching of inner declarations

Review: https://jetbrains.team/p/kt/reviews/13244

Motivation:
    ```
    // Module :lib
    class Foo {
        val member: Int = 2
    }

    // Module :app
    // dependencies { implementation(project(":lib")) }
    class Foo {
        val member: Int = 2
    }
    ```

    Before the commit:
        app_Foo.expectForActual is `null`
        app_Foo.member.expectForActual = lib_foo.member
    After the commit:
        app_Foo.expectForActual is `null`
        app_Foo.member.expectForActual is `null`

    If I don't fix this problem then
    `CommonizerHierarchicalIT.testCommonizeHierarchicallyMultiModule`
    becomes red after I fix KT-59887 in the following commits

    `app_Foo.member.expectForActual = lib_foo.member` happens because we
    also need to match fake-overrides (KT-63550)

I didn't measure it, but theoretically, this commit should be a
performance improvement, becuase we reuse `expectForActual` cache

Additionally, The commit breaks some other tests (e.g.
compiler/testData/diagnostics/tests/multiplatform/headerClass/actualMissing.fir.kt).
The tests will become green again, once I fix KT-59887
This commit is contained in:
Nikita Bobko
2023-11-30 19:04:55 +01:00
committed by Space Team
parent 453d871b25
commit e44e84d1b0
4 changed files with 18 additions and 7 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.mpp.FirExpectActualMatcherTransformer
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
internal object LLFirExpectActualMatcherLazyResolver : LLFirLazyResolver(FirResolvePhase.EXPECT_ACTUAL_MATCHING) {
override fun resolve(
@@ -48,6 +49,16 @@ private class LLFirExpectActualMatchingTargetResolver(
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.EXPECT_ACTUAL_MATCHING) {
private val enabled = session.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
if (enabled) {
// Resolve outer classes before resolving inner declarations. It's the requirement of FirExpectActualResolver
firClass.lazyResolveToPhase(resolverPhase.previous)
performResolve(firClass)
}
action()
}
private val transformer = object : FirExpectActualMatcherTransformer(session, scopeSession) {
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): FirStatement {
transformMemberDeclaration(regularClass)
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.fir.resolve.transformers.mpp
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.ExpectForActualMatchingData
import org.jetbrains.kotlin.fir.declarations.expectForActual
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
@@ -34,15 +34,15 @@ object FirExpectActualResolver {
is FirCallableSymbol<*> -> {
val callableId = actualSymbol.callableId
val classId = callableId.classId
var expectContainingClass: FirRegularClassSymbol? = null
var actualContainingClass: FirRegularClassSymbol? = null
var expectContainingClass: FirRegularClassSymbol? = null
val candidates = when {
classId != null -> {
expectContainingClass = useSiteSession.dependenciesSymbolProvider.getClassLikeSymbolByClassId(classId)?.let {
it.fullyExpandedClass(it.moduleData.session)
}
actualContainingClass = useSiteSession.symbolProvider.getClassLikeSymbolByClassId(classId)
?.fullyExpandedClass(useSiteSession)
expectContainingClass = actualContainingClass?.fir?.expectForActual
?.get(ExpectActualMatchingCompatibility.MatchedSuccessfully)
?.singleOrNull() as? FirRegularClassSymbol
when (actualSymbol) {
is FirConstructorSymbol -> expectContainingClass?.getConstructors(expectScopeSession)
@@ -46,7 +46,7 @@ actual class Bar5 {
}
class Bar6 {
actual constructor()
<!ACTUAL_WITHOUT_EXPECT!>actual constructor()<!>
}
actual class Bar7 actual constructor(s: String) {
@@ -9,5 +9,5 @@ expect class A {
// FILE: jvm.kt
class A {
actual fun foo() {}
actual fun <!ACTUAL_WITHOUT_EXPECT!>foo<!>() {}
}