FIR: Move constructor processing from scopes to tower resolvers

This commit is contained in:
Denis Zharkov
2019-09-16 09:39:08 +03:00
parent 08a8a9fa61
commit fb4b6b8290
7 changed files with 116 additions and 111 deletions
@@ -5,7 +5,8 @@
package org.jetbrains.kotlin.fir.types package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.symbols.* import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
@@ -191,4 +192,4 @@ class ConeIntersectionType(
fun ConeIntersectionType.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionType { fun ConeIntersectionType.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionType {
return ConeIntersectionType(intersectedTypes.map(func)) return ConeIntersectionType(intersectedTypes.map(func))
} }
@@ -52,7 +52,7 @@ class QualifiedReceiverTowerDataConsumer<T : AbstractFirBasedSymbol<*>>(
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
if (kind != TowerDataKind.EMPTY) return ProcessorAction.NEXT if (kind != TowerDataKind.EMPTY) return ProcessorAction.NEXT
return QualifiedReceiverTowerLevel(session).processElementsByName( return QualifiedReceiverTowerLevel(session, candidateFactory.bodyResolveComponents).processElementsByName(
token, token,
name, name,
explicitReceiver, explicitReceiver,
@@ -13,8 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.impl.FirImportImpl import org.jetbrains.kotlin.fir.declarations.impl.FirImportImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump
import org.jetbrains.kotlin.fir.scopes.FirPosition import org.jetbrains.kotlin.fir.scopes.FirPosition
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -25,9 +24,13 @@ import org.jetbrains.kotlin.fir.scopes.processClassifiersByNameWithAction
import org.jetbrains.kotlin.fir.service import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
interface TowerScopeLevel { interface TowerScopeLevel {
@@ -184,7 +187,7 @@ class ScopeTowerLevel(
ProcessorAction.NEXT ProcessorAction.NEXT
} }
} }
TowerScopeLevel.Token.Functions -> scope.processFunctionsByName(name) { candidate -> TowerScopeLevel.Token.Functions -> scope.processFunctionsAndConstructorsByName(name, session, ScopeSession()) { candidate ->
if (candidate.hasConsistentReceivers(extensionReceiver)) { if (candidate.hasConsistentReceivers(extensionReceiver)) {
processor.consumeCandidate( processor.consumeCandidate(
candidate as T, dispatchReceiverValue = candidate.dispatchReceiverValue(), candidate as T, dispatchReceiverValue = candidate.dispatchReceiverValue(),
@@ -207,7 +210,10 @@ class ScopeTowerLevel(
/** /**
* Handles only statics and top-levels, DOES NOT handle objects/companions members * Handles only statics and top-levels, DOES NOT handle objects/companions members
*/ */
class QualifiedReceiverTowerLevel(session: FirSession) : SessionBasedTowerLevel(session) { class QualifiedReceiverTowerLevel(
session: FirSession,
private val bodyResolveComponents: BodyResolveComponents
) : SessionBasedTowerLevel(session) {
override fun <T : AbstractFirBasedSymbol<*>> processElementsByName( override fun <T : AbstractFirBasedSymbol<*>> processElementsByName(
token: TowerScopeLevel.Token<T>, token: TowerScopeLevel.Token<T>,
name: Name, name: Name,
@@ -222,23 +228,29 @@ class QualifiedReceiverTowerLevel(session: FirSession) : SessionBasedTowerLevel(
qualifiedReceiver.packageFqName, qualifiedReceiver.packageFqName,
qualifiedReceiver.relativeClassFqName qualifiedReceiver.relativeClassFqName
) )
), session, ScopeSession() ), session, bodyResolveComponents.scopeSession
) )
@Suppress("UNCHECKED_CAST") val processorForCallables: (FirCallableSymbol<*>) -> ProcessorAction = {
return if (token == TowerScopeLevel.Token.Objects) { val fir = it.fir
scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) { if (fir is FirCallableMemberDeclaration<*> && fir.isStatic || it.callableId.classId == null) {
@Suppress("UNCHECKED_CAST")
processor.consumeCandidate(it as T, null, null)
} else {
ProcessorAction.NEXT
}
}
return when (token) {
TowerScopeLevel.Token.Objects -> scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
@Suppress("UNCHECKED_CAST")
processor.consumeCandidate(it as T, null, null) processor.consumeCandidate(it as T, null, null)
} }
} else { TowerScopeLevel.Token.Functions -> {
scope.processCallables(name, token.cast()) { scope.processFunctionsAndConstructorsByName(name, session, bodyResolveComponents.scopeSession, processorForCallables)
val fir = it.fir
if (fir is FirCallableMemberDeclaration<*> && fir.isStatic || it.callableId.classId == null) {
processor.consumeCandidate(it as T, null, null)
} else {
ProcessorAction.NEXT
}
} }
TowerScopeLevel.Token.Properties -> scope.processPropertiesByName(name, processorForCallables)
} }
} }
} }
@@ -253,4 +265,82 @@ fun FirCallableDeclaration<*>.dispatchReceiverValue(session: FirSession): ClassD
return ClassDispatchReceiverValue(regularClass.symbol) return ClassDispatchReceiverValue(regularClass.symbol)
} }
private fun FirCallableSymbol<*>.hasExtensionReceiver(): Boolean = this.fir.receiverTypeRef != null private fun FirCallableSymbol<*>.hasExtensionReceiver(): Boolean = this.fir.receiverTypeRef != null
private fun FirScope.processFunctionsAndConstructorsByName(
name: Name,
session: FirSession,
scopeSession: ScopeSession,
processor: (FirCallableSymbol<*>) -> ProcessorAction
): ProcessorAction {
val matchedClassSymbol = getFirstClassifierOrNull(name) as? FirClassLikeSymbol<*>
if (processConstructors(
matchedClassSymbol,
processor,
session,
scopeSession,
name
).stop()
) {
return ProcessorAction.STOP
}
return processFunctionsByName(name, processor)
}
private fun FirScope.getFirstClassifierOrNull(name: Name): FirClassifierSymbol<*>? {
var result: FirClassifierSymbol<*>? = null
processClassifiersByNameWithAction(name, FirPosition.OTHER) {
result = it
ProcessorAction.STOP
}
return result
}
private fun finalExpansionName(symbol: FirTypeAliasSymbol, session: FirSession): Name? {
return when (val expandedType = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>()) {
is ConeAbbreviatedType ->
expandedType.abbreviationLookupTag.toSymbol(session)?.safeAs<FirTypeAliasSymbol>()?.let {
finalExpansionName(it, session)
}
else -> expandedType.lookupTag.classId.shortClassName
}
}
private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
processor: (FirFunctionSymbol<*>) -> ProcessorAction,
session: FirSession,
scopeSession: ScopeSession,
name: Name
): ProcessorAction {
try {
if (matchedSymbol != null) {
val scope = when (matchedSymbol) {
is FirTypeAliasSymbol -> matchedSymbol.fir.buildUseSiteScope(session, scopeSession)
is FirClassSymbol -> matchedSymbol.fir.buildUseSiteScope(session, scopeSession)
}
val constructorName = when (matchedSymbol) {
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT
is FirClassSymbol -> name
}
//TODO: why don't we use declared member scope at this point?
if (scope != null && scope.processFunctionsByName(
constructorName,
processor
) == ProcessorAction.STOP
) {
return ProcessorAction.STOP
}
}
return ProcessorAction.NEXT
} catch (e: Throwable) {
throw RuntimeException("While processing constructors", e)
}
}
@@ -8,18 +8,7 @@ package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.buildUseSiteScope
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun MutableList<FirScope>.addImportingScopes(file: FirFile, session: FirSession, scopeSession: ScopeSession) { fun MutableList<FirScope>.addImportingScopes(file: FirFile, session: FirSession, scopeSession: ScopeSession) {
this += listOf( this += listOf(
@@ -39,48 +28,3 @@ fun FirCompositeScope.addImportingScopes(file: FirFile, session: FirSession, sco
scopes.addImportingScopes(file, session, scopeSession) scopes.addImportingScopes(file, session, scopeSession)
} }
private fun finalExpansionName(symbol: FirTypeAliasSymbol, session: FirSession): Name? {
return when (val expandedType = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>()) {
is ConeAbbreviatedType ->
expandedType.abbreviationLookupTag.toSymbol(session)?.safeAs<FirTypeAliasSymbol>()?.let {
finalExpansionName(it, session)
}
else -> expandedType.lookupTag.classId.shortClassName
}
}
fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
processor: (FirFunctionSymbol<*>) -> ProcessorAction,
session: FirSession,
scopeSession: ScopeSession,
name: Name
): ProcessorAction {
try {
if (matchedSymbol != null) {
val scope = when (matchedSymbol) {
is FirTypeAliasSymbol -> matchedSymbol.fir.buildUseSiteScope(session, scopeSession)
is FirClassSymbol -> matchedSymbol.fir.buildUseSiteScope(session, scopeSession)
}
val constructorName = when (matchedSymbol) {
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT
is FirClassSymbol -> name
}
//TODO: why don't we use declared member scope at this point?
if (scope != null && scope.processFunctionsByName(
constructorName,
processor
) == ProcessorAction.STOP
) {
return ProcessorAction.STOP
}
}
return ProcessorAction.NEXT
} catch (e: Throwable) {
throw RuntimeException("While processing constructors", e)
}
}
@@ -13,8 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.TowerScopeLevel
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.processConstructors import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -69,19 +68,6 @@ abstract class FirAbstractImportingScope(
return ProcessorAction.STOP return ProcessorAction.STOP
} }
} else if (name.isSpecial || name.identifier.isNotEmpty()) { } else if (name.isSpecial || name.identifier.isNotEmpty()) {
val matchedClass = provider.getClassLikeSymbolByFqName(ClassId(import.packageFqName, name))
if (processConstructors(
matchedClass,
processor,
session,
scopeSession,
name
).stop()
) {
return ProcessorAction.STOP
}
val symbols = provider.getTopLevelCallableSymbols(callableId.packageName, callableId.callableName) val symbols = provider.getTopLevelCallableSymbols(callableId.packageName, callableId.callableName)
for (symbol in symbols) { for (symbol in symbols) {
@@ -114,4 +100,4 @@ abstract class FirAbstractImportingScope(
) { if (it is FirVariableSymbol<*>) processor(it) else ProcessorAction.NEXT } ) { if (it is FirVariableSymbol<*>) processor(it) else ProcessorAction.NEXT }
} }
} }
@@ -7,38 +7,22 @@ package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.STOP import org.jetbrains.kotlin.fir.scopes.ProcessorAction.STOP
import org.jetbrains.kotlin.fir.scopes.processConstructors
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class FirTopLevelDeclaredMemberScope( class FirTopLevelDeclaredMemberScope(
file: FirFile, file: FirFile,
session: FirSession, session: FirSession,
private val scopeSession: ScopeSession,
lookupInFir: Boolean = true lookupInFir: Boolean = true
) : FirAbstractProviderBasedScope(session, lookupInFir) { ) : FirAbstractProviderBasedScope(session, lookupInFir) {
private val packageFqName = file.packageFqName private val packageFqName = file.packageFqName
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
val matchedClass = provider.getClassLikeSymbolByFqName(ClassId(packageFqName, name))
if (processConstructors(
matchedClass,
processor,
session,
scopeSession,
name
).stop()
) {
return STOP
}
val symbols = provider.getTopLevelCallableSymbols(packageFqName, name) val symbols = provider.getTopLevelCallableSymbols(packageFqName, name)
for (symbol in symbols) { for (symbol in symbols) {
if (symbol is FirFunctionSymbol<*> && !processor(symbol)) { if (symbol is FirFunctionSymbol<*> && !processor(symbol)) {
@@ -10,8 +10,8 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.FirDesignatedBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.fir.resolve.transformers.runResolve
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
@@ -39,7 +39,7 @@ private fun FirFile.findCallableMember(
packageFqName: FqName, klassFqName: FqName?, declName: Name packageFqName: FqName, klassFqName: FqName?, declName: Name
): FirCallableDeclaration<*> { ): FirCallableDeclaration<*> {
val memberScope = val memberScope =
if (klassFqName == null) FirTopLevelDeclaredMemberScope(this, session, ScopeSession()) if (klassFqName == null) FirTopLevelDeclaredMemberScope(this, session)
else provider.getClassDeclaredMemberScope(ClassId(packageFqName, klassFqName, false))!! else provider.getClassDeclaredMemberScope(ClassId(packageFqName, klassFqName, false))!!
var result: FirCallableDeclaration<*>? = null var result: FirCallableDeclaration<*>? = null
val processor = { symbol: FirCallableSymbol<*> -> val processor = { symbol: FirCallableSymbol<*> ->