K2: Optimize use-site member and intersection scopes

Avoid creating cache keys for names that are definitely absent
This commit is contained in:
Denis.Zharkov
2022-12-13 16:45:41 +01:00
committed by Space Team
parent db3b7c4021
commit 24bd7e5eef
3 changed files with 23 additions and 31 deletions
@@ -36,8 +36,6 @@ abstract class AbstractFirUseSiteMemberScope(
protected val propertiesFromSupertypes: MutableMap<Name, List<ResultOfIntersection<FirPropertySymbol>>> = mutableMapOf()
protected val fieldsFromSupertypes: MutableMap<Name, List<FirFieldSymbol>> = mutableMapOf()
private val absentClassifiersFromSupertypes = mutableSetOf<Name>()
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
buildSet {
addAll(declaredMemberScope.getCallableNames())
@@ -53,6 +51,8 @@ abstract class AbstractFirUseSiteMemberScope(
}
final override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getCallableNames()) return
functions.getOrPut(name) {
collectFunctions(name)
}.forEach {
@@ -102,6 +102,8 @@ abstract class AbstractFirUseSiteMemberScope(
}
final override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getCallableNames()) return
properties.getOrPut(name) {
collectProperties(name)
}.forEach {
@@ -198,13 +200,16 @@ abstract class AbstractFirUseSiteMemberScope(
}
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getClassifierNames()) return
var shadowed = false
declaredMemberScope.processClassifiersByNameWithSubstitution(name) { classifier, substitutor ->
shadowed = true
processor(classifier, substitutor)
}
if (!shadowed) {
supertypeScopeContext.processClassifiersByNameWithSubstitution(name, absentClassifiersFromSupertypes, processor)
supertypeScopeContext.processClassifiersByNameWithSubstitution(name, processor)
}
}
@@ -21,41 +21,35 @@ class FirTypeIntersectionScope private constructor(
private val intersectionContext =
FirTypeIntersectionScopeContext(session, overrideChecker, scopes, dispatchReceiverType, forClassUseSiteScope = false)
private val absentFunctions: MutableSet<Name> = mutableSetOf()
private val absentProperties: MutableSet<Name> = mutableSetOf()
private val absentClassifiers: MutableSet<Name> = mutableSetOf()
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<FirCallableSymbol<*>>>> = mutableMapOf()
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
scopes.flatMapTo(mutableSetOf()) { it.getCallableNames() }
}
private val classifiersNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
scopes.flatMapTo(hashSetOf()) { it.getClassifierNames() }
}
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
processCallablesByName(name, processor, absentFunctions, FirScope::processFunctionsByName)
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getCallableNames()) return
processCallablesByName(name, processor, FirScope::processFunctionsByName)
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
processCallablesByName(name, processor, absentProperties, FirScope::processPropertiesByName)
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getCallableNames()) return
processCallablesByName(name, processor, FirScope::processPropertiesByName)
}
private inline fun <D : FirCallableSymbol<*>> processCallablesByName(
name: Name,
noinline processor: (D) -> Unit,
absentNames: MutableSet<Name>,
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
) {
if (name in absentNames) {
return
}
val callablesWithOverridden = intersectionContext.collectIntersectionResultsForCallables(name, processCallables)
if (callablesWithOverridden.isEmpty()) {
absentNames.add(name)
return
}
for (resultOfIntersection in callablesWithOverridden) {
val symbol = resultOfIntersection.chosenSymbol
overriddenSymbols[symbol] = resultOfIntersection.overriddenMembers
@@ -64,7 +58,9 @@ class FirTypeIntersectionScope private constructor(
}
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
intersectionContext.processClassifiersByNameWithSubstitution(name, absentClassifiers, processor)
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getClassifierNames()) return
intersectionContext.processClassifiersByNameWithSubstitution(name, processor)
}
@Suppress("UNCHECKED_CAST")
@@ -112,9 +108,7 @@ class FirTypeIntersectionScope private constructor(
override fun getCallableNames(): Set<Name> = callableNamesCached
override fun getClassifierNames(): Set<Name> {
return scopes.flatMapTo(hashSetOf()) { it.getClassifierNames() }
}
override fun getClassifierNames(): Set<Name> = classifiersNamesCached
override fun toString(): String {
return "Intersection of [${scopes.joinToString(", ")}]"
@@ -76,16 +76,9 @@ class FirTypeIntersectionScopeContext(
fun processClassifiersByNameWithSubstitution(
name: Name,
absentClassifierNames: MutableSet<Name>,
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
) {
if (name in absentClassifierNames) return
val classifiers = collectClassifiers(name)
if (classifiers.isEmpty()) {
absentClassifierNames += name
return
}
for ((symbol, substitution) in classifiers) {
for ((symbol, substitution) in collectClassifiers(name)) {
processor(symbol, substitution)
}
}