[FIR] Use both context and code fragment imports

This commit is contained in:
Yan Zhulanow
2023-06-20 03:02:40 +09:00
parent 33abe75a74
commit 92198ee016
3 changed files with 56 additions and 37 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.fir.resolve.inference.FirInferenceSession
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.resolve.transformers.withScopeCleanup
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.computeImportingScopes
import org.jetbrains.kotlin.fir.scopes.createImportingScopes
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
@@ -529,9 +530,16 @@ class BodyResolveContext(
}
}
fun <T> withScopesForCodeFragment(codeFragment: FirCodeFragment, f: () -> T): T {
fun <T> withScopesForCodeFragment(codeFragment: FirCodeFragment, holder: SessionHolder, f: () -> T): T {
val towerDataContext = codeFragment.towerDataContext ?: error("Context is not set for a code fragment")
val base = towerDataContext.addNonLocalTowerDataElements(towerDataContext.nonLocalTowerDataElements)
val fragmentImportTowerDataElements = computeImportingScopes(file, holder.session, holder.scopeSession)
.map { it.asTowerDataElement(isLocal = false) }
val base = towerDataContext
.addNonLocalTowerDataElements(towerDataContext.nonLocalTowerDataElements)
.addNonLocalTowerDataElements(fragmentImportTowerDataElements)
val baseWithLocalScope = towerDataContext.localScopes.fold(base) { acc, scope -> acc.addLocalScope(scope) }
val newContext = FirRegularTowerDataContexts(
@@ -545,7 +545,7 @@ open class FirDeclarationsResolveTransformer(
override fun transformCodeFragment(codeFragment: FirCodeFragment, data: ResolutionMode): FirCodeFragment {
dataFlowAnalyzer.enterCodeFragment(codeFragment)
context.withScopesForCodeFragment(codeFragment) {
context.withScopesForCodeFragment(codeFragment, components) {
transformBlock(codeFragment.block, data)
}
dataFlowAnalyzer.exitCodeFragment()
@@ -27,16 +27,18 @@ fun createImportingScopes(
useCaching: Boolean = true
): List<FirScope> = if (useCaching) {
scopeSession.getOrBuild(file, ALL_IMPORTS) {
ListStorageFirScope(doCreateImportingScopes(file, session, scopeSession))
ListStorageFirScope(computeImportingScopes(file, session, scopeSession))
}.result
} else {
doCreateImportingScopes(file, session, scopeSession)
computeImportingScopes(file, session, scopeSession)
}
private fun doCreateImportingScopes(
internal fun computeImportingScopes(
file: FirFile,
session: FirSession,
scopeSession: ScopeSession
scopeSession: ScopeSession,
includeDefaultImports: Boolean = true,
includePackageImport: Boolean = true
): List<FirScope> {
file.lazyResolveToPhase(FirResolvePhase.IMPORTS)
val excludedImportNames =
@@ -47,38 +49,47 @@ private fun doCreateImportingScopes(
if (it.parent() == file.packageFqName) it.shortName() else null
}
return listOf(
FirDefaultStarImportingScope(
scopeSession.getOrBuild(DefaultStarImportKey(DefaultImportPriority.HIGH, excludedImportNames), DEFAULT_STAR_IMPORT) {
FirSingleLevelDefaultStarImportingScope(session, scopeSession, DefaultImportPriority.HIGH, excludedImportNames)
},
scopeSession.getOrBuild(DefaultStarImportKey(DefaultImportPriority.LOW, excludedImportNames), DEFAULT_STAR_IMPORT) {
FirSingleLevelDefaultStarImportingScope(session, scopeSession, DefaultImportPriority.LOW, excludedImportNames)
},
),
return buildList {
if (includeDefaultImports) {
this += FirDefaultStarImportingScope(
scopeSession.getOrBuild(DefaultStarImportKey(DefaultImportPriority.HIGH, excludedImportNames), DEFAULT_STAR_IMPORT) {
FirSingleLevelDefaultStarImportingScope(session, scopeSession, DefaultImportPriority.HIGH, excludedImportNames)
},
scopeSession.getOrBuild(DefaultStarImportKey(DefaultImportPriority.LOW, excludedImportNames), DEFAULT_STAR_IMPORT) {
FirSingleLevelDefaultStarImportingScope(session, scopeSession, DefaultImportPriority.LOW, excludedImportNames)
},
)
scopeSession.getOrBuild(DefaultImportPriority.KOTLIN_THROWS, DEFAULT_SIMPLE_IMPORT) {
FirDefaultSimpleImportingScope(session, scopeSession, priority = DefaultImportPriority.KOTLIN_THROWS)
},
FirExplicitStarImportingScope(file.imports, session, scopeSession, excludedImportNames),
this += scopeSession.getOrBuild(DefaultImportPriority.KOTLIN_THROWS, DEFAULT_SIMPLE_IMPORT) {
FirDefaultSimpleImportingScope(session, scopeSession, priority = DefaultImportPriority.KOTLIN_THROWS)
}
}
scopeSession.getOrBuild(DefaultImportPriority.LOW, DEFAULT_SIMPLE_IMPORT) {
FirDefaultSimpleImportingScope(session, scopeSession, priority = DefaultImportPriority.LOW)
},
scopeSession.getOrBuild(DefaultImportPriority.HIGH, DEFAULT_SIMPLE_IMPORT) {
FirDefaultSimpleImportingScope(session, scopeSession, priority = DefaultImportPriority.HIGH)
},
when {
excludedNamesInPackage.isEmpty() ->
// Supposed to be the most common branch, so we cache it
scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
FirPackageMemberScope(file.packageFqName, session, excludedNames = emptySet())
}
else ->
FirPackageMemberScope(file.packageFqName, session, excludedNames = excludedNamesInPackage)
},
FirExplicitSimpleImportingScope(file.imports, session, scopeSession)
)
this += FirExplicitStarImportingScope(file.imports, session, scopeSession, excludedImportNames)
if (includeDefaultImports) {
this += scopeSession.getOrBuild(DefaultImportPriority.LOW, DEFAULT_SIMPLE_IMPORT) {
FirDefaultSimpleImportingScope(session, scopeSession, priority = DefaultImportPriority.LOW)
}
this += scopeSession.getOrBuild(DefaultImportPriority.HIGH, DEFAULT_SIMPLE_IMPORT) {
FirDefaultSimpleImportingScope(session, scopeSession, priority = DefaultImportPriority.HIGH)
}
}
if (includePackageImport) {
this += when {
excludedNamesInPackage.isEmpty() ->
// Supposed to be the most common branch, so we cache it
scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
FirPackageMemberScope(file.packageFqName, session, excludedNames = emptySet())
}
else ->
FirPackageMemberScope(file.packageFqName, session, excludedNames = excludedNamesInPackage)
}
}
// TODO: explicit simple importing scope should have highest priority (higher than inner scopes added in process)
this += FirExplicitSimpleImportingScope(file.imports, session, scopeSession)
}
}
private class ListStorageFirScope(val result: List<FirScope>) : FirScope()