[FIR] Refactoring. Split CallResolver.kt to several files
This commit is contained in:
committed by
Mikhail Glukhikh
parent
3c7b25b8c9
commit
8bbb60df25
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
sealed class CallKind {
|
||||
abstract fun sequence(): List<ResolutionStage>
|
||||
|
||||
object Function : CallKind() {
|
||||
override fun sequence(): List<ResolutionStage> {
|
||||
return functionCallResolutionSequence()
|
||||
}
|
||||
}
|
||||
|
||||
object VariableAccess : CallKind() {
|
||||
override fun sequence(): List<ResolutionStage> {
|
||||
return qualifiedAccessResolutionSequence()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun functionCallResolutionSequence() = listOf(
|
||||
CheckVisibility,
|
||||
MapArguments,
|
||||
CheckExplicitReceiverConsistency,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension,
|
||||
CheckArguments
|
||||
)
|
||||
|
||||
|
||||
internal fun qualifiedAccessResolutionSequence() = listOf(
|
||||
CheckVisibility,
|
||||
DiscriminateSynthetics,
|
||||
CheckExplicitReceiverConsistency,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension
|
||||
)
|
||||
@@ -5,749 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirImportImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.constructClassType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
|
||||
import org.jetbrains.kotlin.fir.scopes.processClassifiersByNameWithAction
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.createCoroutineUnintercepted
|
||||
|
||||
class CallInfo(
|
||||
val callKind: CallKind,
|
||||
|
||||
val explicitReceiver: FirExpression?,
|
||||
val arguments: List<FirExpression>,
|
||||
val isSafeCall: Boolean,
|
||||
|
||||
val typeArguments: List<FirTypeProjection>,
|
||||
val session: FirSession,
|
||||
val containingFile: FirFile,
|
||||
val container: FirDeclaration,
|
||||
val typeProvider: (FirExpression) -> FirTypeRef?
|
||||
) {
|
||||
val argumentCount get() = arguments.size
|
||||
}
|
||||
|
||||
interface CheckerSink {
|
||||
fun reportApplicability(new: CandidateApplicability)
|
||||
suspend fun yield()
|
||||
suspend fun yieldApplicability(new: CandidateApplicability) {
|
||||
reportApplicability(new)
|
||||
yield()
|
||||
}
|
||||
|
||||
val components: InferenceComponents
|
||||
|
||||
suspend fun yieldIfNeed()
|
||||
}
|
||||
|
||||
|
||||
class CheckerSinkImpl(override val components: InferenceComponents, var continuation: Continuation<Unit>? = null) : CheckerSink {
|
||||
var current = CandidateApplicability.RESOLVED
|
||||
override fun reportApplicability(new: CandidateApplicability) {
|
||||
if (new < current) current = new
|
||||
}
|
||||
|
||||
override suspend fun yield() = kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn<Unit> {
|
||||
continuation = it
|
||||
kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
override suspend fun yieldIfNeed() {
|
||||
if (current < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
yield()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Candidate(
|
||||
val symbol: FirBasedSymbol<*>,
|
||||
val dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
val implicitExtensionReceiverValue: ImplicitReceiverValue?,
|
||||
val explicitReceiverKind: ExplicitReceiverKind,
|
||||
private val inferenceComponents: InferenceComponents,
|
||||
private val baseSystem: ConstraintStorage,
|
||||
val callInfo: CallInfo
|
||||
) {
|
||||
val system by lazy {
|
||||
val system = inferenceComponents.createConstraintSystem()
|
||||
system.addOtherSystem(baseSystem)
|
||||
system
|
||||
}
|
||||
lateinit var substitutor: ConeSubstitutor
|
||||
|
||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||
val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>()
|
||||
}
|
||||
|
||||
sealed class CallKind {
|
||||
abstract fun sequence(): List<ResolutionStage>
|
||||
|
||||
object Function : CallKind() {
|
||||
override fun sequence(): List<ResolutionStage> {
|
||||
return functionCallResolutionSequence()
|
||||
}
|
||||
}
|
||||
|
||||
object VariableAccess : CallKind() {
|
||||
override fun sequence(): List<ResolutionStage> {
|
||||
return qualifiedAccessResolutionSequence()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class TowerDataKind {
|
||||
EMPTY,
|
||||
TOWER_LEVEL
|
||||
}
|
||||
|
||||
interface TowerScopeLevel {
|
||||
|
||||
sealed class Token<out T : FirBasedSymbol<*>> {
|
||||
object Properties : Token<FirPropertySymbol>()
|
||||
|
||||
object Functions : Token<FirFunctionSymbol<*>>()
|
||||
object Objects : Token<FirBasedSymbol<*>>()
|
||||
}
|
||||
|
||||
fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction
|
||||
|
||||
interface TowerScopeLevelProcessor<T : ConeSymbol> {
|
||||
fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction
|
||||
}
|
||||
|
||||
object Empty : TowerScopeLevel {
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction = ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SessionBasedTowerLevel(val session: FirSession) : TowerScopeLevel {
|
||||
protected fun FirBasedSymbol<*>.dispatchReceiverValue(): ClassDispatchReceiverValue? {
|
||||
return when (this) {
|
||||
is FirNamedFunctionSymbol -> fir.dispatchReceiverValue(session)
|
||||
is FirClassSymbol -> ClassDispatchReceiverValue(fir.symbol)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
protected fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(extensionReceiver: ReceiverValue?): Boolean {
|
||||
val hasExtensionReceiver = hasExtensionReceiver()
|
||||
return hasExtensionReceiver == (extensionReceiver != null)
|
||||
}
|
||||
}
|
||||
|
||||
// This is more like "dispatch receiver-based tower level"
|
||||
// Here we always have an explicit or implicit dispatch receiver, and can access members of its scope
|
||||
// (which is separated from currently accessible scope, see below)
|
||||
// So: dispatch receiver = given explicit or implicit receiver (always present)
|
||||
// So: extension receiver = either none, if dispatch receiver = explicit receiver,
|
||||
// or given implicit or explicit receiver, otherwise
|
||||
class MemberScopeTowerLevel(
|
||||
session: FirSession,
|
||||
val dispatchReceiver: ReceiverValue,
|
||||
val implicitExtensionReceiver: ImplicitReceiverValue? = null,
|
||||
val scopeSession: ScopeSession
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
|
||||
private fun <T : FirBasedSymbol<*>> processMembers(
|
||||
output: TowerScopeLevel.TowerScopeLevelProcessor<T>,
|
||||
explicitExtensionReceiver: ExpressionReceiverValue?,
|
||||
processScopeMembers: FirScope.(processor: (T) -> ProcessorAction) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
if (implicitExtensionReceiver != null && explicitExtensionReceiver != null) return ProcessorAction.NEXT
|
||||
val extensionReceiver = implicitExtensionReceiver ?: explicitExtensionReceiver
|
||||
val scope = dispatchReceiver.type.scope(session, scopeSession) ?: return ProcessorAction.NEXT
|
||||
if (scope.processScopeMembers { candidate ->
|
||||
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(extensionReceiver)) {
|
||||
// NB: we do not check dispatchReceiverValue != null here,
|
||||
// because of objects & constructors (see comments in dispatchReceiverValue() implementation)
|
||||
output.consumeCandidate(candidate, candidate.dispatchReceiverValue(), implicitExtensionReceiver)
|
||||
} else if (candidate is FirClassLikeSymbol<*>) {
|
||||
output.consumeCandidate(candidate, null, implicitExtensionReceiver)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}.stop()
|
||||
) return ProcessorAction.STOP
|
||||
val withSynthetic = FirSyntheticPropertiesScope(session, scope, ReturnTypeCalculatorWithJump(session, scopeSession))
|
||||
return withSynthetic.processScopeMembers { symbol ->
|
||||
output.consumeCandidate(symbol, symbol.dispatchReceiverValue(), implicitExtensionReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
val explicitExtensionReceiver = if (dispatchReceiver == explicitReceiver) null else explicitReceiver
|
||||
return when (token) {
|
||||
TowerScopeLevel.Token.Properties -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processPropertiesByName(name, symbol.cast())
|
||||
}
|
||||
TowerScopeLevel.Token.Functions -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processFunctionsByName(name, symbol.cast())
|
||||
}
|
||||
TowerScopeLevel.Token.Objects -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processClassifiersByNameWithAction(name, FirPosition.OTHER, symbol.cast())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.hasExtensionReceiver(): Boolean = this.fir.receiverTypeRef != null
|
||||
|
||||
// This is more like "scope-based tower level"
|
||||
// We can access here members of currently accessible scope which is not influenced by explicit receiver
|
||||
// We can either have no explicit receiver at all, or it can be an extension receiver
|
||||
// An explicit receiver never can be a dispatch receiver at this level
|
||||
// So: dispatch receiver = strictly NONE
|
||||
// So: extension receiver = either none or explicit
|
||||
// (if explicit receiver exists, it always *should* be an extension receiver)
|
||||
class ScopeTowerLevel(
|
||||
session: FirSession,
|
||||
val scope: FirScope,
|
||||
val implicitExtensionReceiver: ImplicitReceiverValue? = null
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
if (explicitReceiver != null && implicitExtensionReceiver != null) {
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
val extensionReceiver = explicitReceiver ?: implicitExtensionReceiver
|
||||
return when (token) {
|
||||
|
||||
TowerScopeLevel.Token.Properties -> scope.processPropertiesByName(name) { candidate ->
|
||||
if (candidate.hasConsistentExtensionReceiver(extensionReceiver) && candidate.dispatchReceiverValue() == null) {
|
||||
processor.consumeCandidate(
|
||||
candidate as T, dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = implicitExtensionReceiver
|
||||
)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
TowerScopeLevel.Token.Functions -> scope.processFunctionsByName(name) { candidate ->
|
||||
if (candidate.hasConsistentExtensionReceiver(extensionReceiver) && candidate.dispatchReceiverValue() == null) {
|
||||
processor.consumeCandidate(
|
||||
candidate as T, dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = implicitExtensionReceiver
|
||||
)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
TowerScopeLevel.Token.Objects -> scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
|
||||
processor.consumeCandidate(
|
||||
it as T, dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles only statics and top-levels, DOES NOT handle objects/companions members
|
||||
*/
|
||||
class QualifiedReceiverTowerLevel(session: FirSession) : SessionBasedTowerLevel(session) {
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
val qualifiedReceiver = explicitReceiver?.explicitReceiverExpression as FirResolvedQualifier
|
||||
val scope = FirExplicitSimpleImportingScope(
|
||||
listOf(
|
||||
FirResolvedImportImpl(
|
||||
session,
|
||||
FirImportImpl(session, null, FqName.topLevel(name), false, null),
|
||||
qualifiedReceiver.packageFqName,
|
||||
qualifiedReceiver.relativeClassFqName
|
||||
)
|
||||
), session
|
||||
)
|
||||
|
||||
return if (token == TowerScopeLevel.Token.Objects) {
|
||||
scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
|
||||
processor.consumeCandidate(it as T, null, null)
|
||||
}
|
||||
} else {
|
||||
scope.processCallables(name, token.cast()) {
|
||||
val fir = it.fir
|
||||
if (fir is FirCallableMemberDeclaration<*> && fir.isStatic || it.callableId.classId == null) {
|
||||
processor.consumeCandidate(it as T, null, null)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class QualifiedReceiverTowerDataConsumer<T : FirBasedSymbol<*>>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val explicitReceiver: ExpressionReceiverValue,
|
||||
val candidateFactory: CandidateFactory,
|
||||
val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
if (kind != TowerDataKind.EMPTY) return ProcessorAction.NEXT
|
||||
|
||||
return QualifiedReceiverTowerLevel(session).processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
assert(dispatchReceiverValue == null)
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = null,
|
||||
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class TowerDataConsumer {
|
||||
abstract fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
// resultCollector: CandidateCollector,
|
||||
group: Int
|
||||
): ProcessorAction
|
||||
|
||||
private var stopGroup = Int.MAX_VALUE
|
||||
fun skipGroup(group: Int, resultCollector: CandidateCollector): Boolean {
|
||||
if (resultCollector.isSuccess() && stopGroup == Int.MAX_VALUE) {
|
||||
stopGroup = group
|
||||
}
|
||||
if (group >= stopGroup) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun createVariableAndObjectConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector
|
||||
): TowerDataConsumer {
|
||||
return PrioritizedTowerDataConsumer(
|
||||
resultCollector,
|
||||
createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Properties,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
),
|
||||
createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Objects,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
fun createSimpleFunctionConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector
|
||||
): TowerDataConsumer {
|
||||
return createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Functions,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
)
|
||||
}
|
||||
|
||||
fun createFunctionConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector,
|
||||
callResolver: CallResolver
|
||||
): TowerDataConsumer {
|
||||
val varCallInfo = CallInfo(
|
||||
CallKind.VariableAccess,
|
||||
callInfo.explicitReceiver,
|
||||
emptyList(),
|
||||
callInfo.isSafeCall,
|
||||
callInfo.typeArguments,
|
||||
inferenceComponents.session,
|
||||
callInfo.containingFile,
|
||||
callInfo.container,
|
||||
callInfo.typeProvider
|
||||
)
|
||||
return PrioritizedTowerDataConsumer(
|
||||
resultCollector,
|
||||
createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Functions,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
),
|
||||
AccumulatingTowerDataConsumer(resultCollector).apply {
|
||||
initialConsumer = createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Properties,
|
||||
varCallInfo,
|
||||
inferenceComponents,
|
||||
InvokeReceiverCandidateCollector(
|
||||
callResolver,
|
||||
invokeCallInfo = callInfo,
|
||||
components = inferenceComponents,
|
||||
invokeConsumer = this
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun createSimpleConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
token: TowerScopeLevel.Token<*>,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector
|
||||
): TowerDataConsumer {
|
||||
val factory = CandidateFactory(inferenceComponents, callInfo)
|
||||
val explicitReceiver = callInfo.explicitReceiver
|
||||
return if (explicitReceiver != null) {
|
||||
val receiverValue = ExpressionReceiverValue(explicitReceiver, callInfo.typeProvider)
|
||||
if (explicitReceiver is FirResolvedQualifier) {
|
||||
val qualified =
|
||||
QualifiedReceiverTowerDataConsumer(session, name, token, receiverValue, factory, resultCollector)
|
||||
|
||||
if (explicitReceiver.classId != null) {
|
||||
PrioritizedTowerDataConsumer(
|
||||
resultCollector,
|
||||
qualified,
|
||||
ExplicitReceiverTowerDataConsumer(session, name, token, receiverValue, factory, resultCollector)
|
||||
)
|
||||
} else {
|
||||
qualified
|
||||
}
|
||||
|
||||
} else {
|
||||
ExplicitReceiverTowerDataConsumer(session, name, token, receiverValue, factory, resultCollector)
|
||||
}
|
||||
} else {
|
||||
NoExplicitReceiverTowerDataConsumer(session, name, token, factory, resultCollector)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PrioritizedTowerDataConsumer(
|
||||
val resultCollector: CandidateCollector,
|
||||
vararg val consumers: TowerDataConsumer
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
for ((index, consumer) in consumers.withIndex()) {
|
||||
val action = consumer.consume(kind, towerScopeLevel, group * consumers.size + index)
|
||||
if (action.stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
// Yet is used exclusively for invokes:
|
||||
// - initialConsumer consumes property which is invoke receiver
|
||||
// - additionalConsumers consume invoke calls themselves
|
||||
class AccumulatingTowerDataConsumer(
|
||||
private val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
lateinit var initialConsumer: TowerDataConsumer
|
||||
private val additionalConsumers = mutableListOf<TowerDataConsumer>()
|
||||
|
||||
private data class TowerData(val kind: TowerDataKind, val level: TowerScopeLevel, val group: Int)
|
||||
|
||||
private val accumulatedTowerData = mutableListOf<TowerData>()
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
accumulatedTowerData += TowerData(kind, towerScopeLevel, group)
|
||||
|
||||
if (initialConsumer.consume(kind, towerScopeLevel, group).stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
for (consumer in additionalConsumers) {
|
||||
val action = consumer.consume(kind, towerScopeLevel, group)
|
||||
if (action.stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
fun addConsumer(consumer: TowerDataConsumer): ProcessorAction {
|
||||
additionalConsumers += consumer
|
||||
for ((kind, level, group) in accumulatedTowerData) {
|
||||
if (consumer.consume(kind, level, group).stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
class ExplicitReceiverTowerDataConsumer<T : FirBasedSymbol<*>>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val explicitReceiver: ExpressionReceiverValue,
|
||||
val candidateFactory: CandidateFactory,
|
||||
val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
companion object {
|
||||
val defaultPackage = Name.identifier("kotlin")
|
||||
}
|
||||
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
return when (kind) {
|
||||
TowerDataKind.EMPTY ->
|
||||
MemberScopeTowerLevel(session, explicitReceiver, scopeSession = candidateFactory.inferenceComponents.scopeSession)
|
||||
.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver = null,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
implicitExtensionReceiverValue,
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
)
|
||||
TowerDataKind.TOWER_LEVEL -> {
|
||||
if (token == TowerScopeLevel.Token.Objects) return ProcessorAction.NEXT
|
||||
towerScopeLevel.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver = explicitReceiver,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
if (symbol is FirNamedFunctionSymbol && symbol.callableId.packageName.startsWith(defaultPackage)) {
|
||||
val explicitReceiverType = explicitReceiver.type
|
||||
if (dispatchReceiverValue == null && explicitReceiverType is ConeClassType) {
|
||||
val declarationReceiverTypeRef =
|
||||
(symbol as? FirCallableSymbol<*>)?.fir?.receiverTypeRef as? FirResolvedTypeRef
|
||||
val declarationReceiverType = declarationReceiverTypeRef?.type
|
||||
if (declarationReceiverType is ConeClassType) {
|
||||
if (!AbstractTypeChecker.isSubtypeOf(
|
||||
candidateFactory.inferenceComponents.ctx,
|
||||
explicitReceiverType,
|
||||
declarationReceiverType.lookupTag.constructClassType(
|
||||
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(),
|
||||
isNullable = true
|
||||
)
|
||||
)
|
||||
) {
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val candidate = candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
implicitExtensionReceiverValue,
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidate
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class NoExplicitReceiverTowerDataConsumer<T : FirBasedSymbol<*>>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val candidateFactory: CandidateFactory,
|
||||
val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
return when (kind) {
|
||||
|
||||
TowerDataKind.TOWER_LEVEL -> {
|
||||
towerScopeLevel.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver = null,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
implicitExtensionReceiverValue,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CallResolver(val typeCalculator: ReturnTypeCalculator, val components: InferenceComponents) {
|
||||
|
||||
var callInfo: CallInfo? = null
|
||||
|
||||
var scopes: List<FirScope>? = null
|
||||
|
||||
val session: FirSession get() = components.session
|
||||
@@ -792,7 +60,6 @@ class CallResolver(val typeCalculator: ReturnTypeCalculator, val components: Inf
|
||||
towerDataConsumer = consumer
|
||||
|
||||
var group = 0
|
||||
|
||||
towerDataConsumer.consume(TowerDataKind.EMPTY, TowerScopeLevel.Empty, group++)
|
||||
|
||||
for (scope in scopes!!) {
|
||||
@@ -812,168 +79,6 @@ class CallResolver(val typeCalculator: ReturnTypeCalculator, val components: Inf
|
||||
group = processImplicitReceiver(towerDataConsumer, implicitReceiverValue, collector, group)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return collector
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum class CandidateApplicability {
|
||||
HIDDEN,
|
||||
WRONG_RECEIVER,
|
||||
PARAMETER_MAPPING_ERROR,
|
||||
INAPPLICABLE,
|
||||
SYNTHETIC_RESOLVED,
|
||||
RESOLVED
|
||||
}
|
||||
|
||||
open class CandidateCollector(val components: InferenceComponents) {
|
||||
|
||||
val groupNumbers = mutableListOf<Int>()
|
||||
val candidates = mutableListOf<Candidate>()
|
||||
|
||||
|
||||
var currentApplicability = CandidateApplicability.HIDDEN
|
||||
|
||||
|
||||
fun newDataSet() {
|
||||
groupNumbers.clear()
|
||||
candidates.clear()
|
||||
currentApplicability = CandidateApplicability.HIDDEN
|
||||
}
|
||||
|
||||
protected fun getApplicability(
|
||||
group: Int,
|
||||
candidate: Candidate
|
||||
): CandidateApplicability {
|
||||
|
||||
val sink = CheckerSinkImpl(components)
|
||||
var finished = false
|
||||
sink.continuation = suspend {
|
||||
for (stage in candidate.callInfo.callKind.sequence()) {
|
||||
stage.check(candidate, sink, candidate.callInfo)
|
||||
}
|
||||
}.createCoroutineUnintercepted(completion = object : Continuation<Unit> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
override fun resumeWith(result: Result<Unit>) {
|
||||
result.exceptionOrNull()?.let { throw it }
|
||||
finished = true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
while (!finished) {
|
||||
sink.continuation!!.resume(Unit)
|
||||
if (sink.current < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return sink.current
|
||||
}
|
||||
|
||||
open fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
|
||||
val applicability = getApplicability(group, candidate)
|
||||
|
||||
if (applicability > currentApplicability) {
|
||||
groupNumbers.clear()
|
||||
candidates.clear()
|
||||
currentApplicability = applicability
|
||||
}
|
||||
|
||||
|
||||
if (applicability == currentApplicability) {
|
||||
candidates.add(candidate)
|
||||
groupNumbers.add(group)
|
||||
}
|
||||
|
||||
return applicability
|
||||
}
|
||||
|
||||
|
||||
fun bestCandidates(): List<Candidate> {
|
||||
if (groupNumbers.isEmpty()) return emptyList()
|
||||
if (groupNumbers.size == 1) return candidates
|
||||
val result = mutableListOf<Candidate>()
|
||||
var bestGroup = groupNumbers.first()
|
||||
for ((index, candidate) in candidates.withIndex()) {
|
||||
val group = groupNumbers[index]
|
||||
if (bestGroup > group) {
|
||||
bestGroup = group
|
||||
result.clear()
|
||||
}
|
||||
if (bestGroup == group) {
|
||||
result.add(candidate)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun isSuccess(): Boolean {
|
||||
return currentApplicability == CandidateApplicability.RESOLVED
|
||||
}
|
||||
}
|
||||
|
||||
// Collects properties that potentially could be invoke receivers, like 'propertyName()',
|
||||
// and initiates further invoke resolution by adding property-bound invoke consumers
|
||||
class InvokeReceiverCandidateCollector(
|
||||
val callResolver: CallResolver,
|
||||
val invokeCallInfo: CallInfo,
|
||||
components: InferenceComponents,
|
||||
val invokeConsumer: AccumulatingTowerDataConsumer
|
||||
) : CandidateCollector(components) {
|
||||
override fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
|
||||
val applicability = super.consumeCandidate(group, candidate)
|
||||
|
||||
if (applicability >= CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
|
||||
val session = components.session
|
||||
val boundInvokeCallInfo = CallInfo(
|
||||
invokeCallInfo.callKind,
|
||||
FirQualifiedAccessExpressionImpl(session, null, false).apply {
|
||||
calleeReference = FirNamedReferenceWithCandidate(
|
||||
session,
|
||||
null,
|
||||
(candidate.symbol as ConeCallableSymbol).callableId.callableName,
|
||||
candidate
|
||||
)
|
||||
typeRef = callResolver.typeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe())
|
||||
},
|
||||
invokeCallInfo.arguments,
|
||||
invokeCallInfo.isSafeCall,
|
||||
invokeCallInfo.typeArguments,
|
||||
session,
|
||||
invokeCallInfo.containingFile,
|
||||
invokeCallInfo.container,
|
||||
invokeCallInfo.typeProvider
|
||||
)
|
||||
|
||||
invokeConsumer.addConsumer(
|
||||
createSimpleFunctionConsumer(
|
||||
session, OperatorNameConventions.INVOKE,
|
||||
boundInvokeCallInfo, components, callResolver.collector
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return applicability
|
||||
}
|
||||
}
|
||||
|
||||
fun FirCallableDeclaration<*>.dispatchReceiverValue(session: FirSession): ClassDispatchReceiverValue? {
|
||||
// TODO: this is not true at least for inner class constructors
|
||||
if (this is FirConstructor) return null
|
||||
val id = (this.symbol as ConeCallableSymbol).callableId.classId ?: return null
|
||||
val symbol = session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(id) as? FirClassSymbol ?: return null
|
||||
val regularClass = symbol.fir
|
||||
|
||||
// TODO: this is also not true, but objects can be also imported
|
||||
if (regularClass.classKind == ClassKind.OBJECT) return null
|
||||
|
||||
return ClassDispatchReceiverValue(regularClass.symbol)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
|
||||
class CallInfo(
|
||||
val callKind: CallKind,
|
||||
|
||||
val explicitReceiver: FirExpression?,
|
||||
val arguments: List<FirExpression>,
|
||||
val isSafeCall: Boolean,
|
||||
|
||||
val typeArguments: List<FirTypeProjection>,
|
||||
val session: FirSession,
|
||||
val containingFile: FirFile,
|
||||
val container: FirDeclaration,
|
||||
val typeProvider: (FirExpression) -> FirTypeRef?
|
||||
) {
|
||||
val argumentCount get() = arguments.size
|
||||
}
|
||||
|
||||
enum class CandidateApplicability {
|
||||
HIDDEN,
|
||||
WRONG_RECEIVER,
|
||||
PARAMETER_MAPPING_ERROR,
|
||||
INAPPLICABLE,
|
||||
SYNTHETIC_RESOLVED,
|
||||
RESOLVED
|
||||
}
|
||||
|
||||
class Candidate(
|
||||
val symbol: FirBasedSymbol<*>,
|
||||
val dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
val implicitExtensionReceiverValue: ImplicitReceiverValue?,
|
||||
val explicitReceiverKind: ExplicitReceiverKind,
|
||||
private val inferenceComponents: InferenceComponents,
|
||||
private val baseSystem: ConstraintStorage,
|
||||
val callInfo: CallInfo
|
||||
) {
|
||||
val system by lazy {
|
||||
val system = inferenceComponents.createConstraintSystem()
|
||||
system.addOtherSystem(baseSystem)
|
||||
system
|
||||
}
|
||||
lateinit var substitutor: ConeSubstitutor
|
||||
|
||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||
val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>()
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.coroutines.intrinsics.createCoroutineUnintercepted
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
open class CandidateCollector(val components: InferenceComponents) {
|
||||
|
||||
val groupNumbers = mutableListOf<Int>()
|
||||
val candidates = mutableListOf<Candidate>()
|
||||
|
||||
var currentApplicability = CandidateApplicability.HIDDEN
|
||||
|
||||
fun newDataSet() {
|
||||
groupNumbers.clear()
|
||||
candidates.clear()
|
||||
currentApplicability = CandidateApplicability.HIDDEN
|
||||
}
|
||||
|
||||
private fun getApplicability(
|
||||
group: Int,
|
||||
candidate: Candidate
|
||||
): CandidateApplicability {
|
||||
val sink = CheckerSinkImpl(components)
|
||||
var finished = false
|
||||
sink.continuation = suspend {
|
||||
for (stage in candidate.callInfo.callKind.sequence()) {
|
||||
stage.check(candidate, sink, candidate.callInfo)
|
||||
}
|
||||
}.createCoroutineUnintercepted(completion = object : Continuation<Unit> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
override fun resumeWith(result: Result<Unit>) {
|
||||
result.exceptionOrNull()?.let { throw it }
|
||||
finished = true
|
||||
}
|
||||
})
|
||||
|
||||
while (!finished) {
|
||||
sink.continuation!!.resume(Unit)
|
||||
if (sink.current < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return sink.current
|
||||
}
|
||||
|
||||
open fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
|
||||
val applicability = getApplicability(group, candidate)
|
||||
|
||||
if (applicability > currentApplicability) {
|
||||
groupNumbers.clear()
|
||||
candidates.clear()
|
||||
currentApplicability = applicability
|
||||
}
|
||||
|
||||
if (applicability == currentApplicability) {
|
||||
candidates.add(candidate)
|
||||
groupNumbers.add(group)
|
||||
}
|
||||
|
||||
return applicability
|
||||
}
|
||||
|
||||
fun bestCandidates(): List<Candidate> {
|
||||
if (groupNumbers.isEmpty()) return emptyList()
|
||||
if (groupNumbers.size == 1) return candidates
|
||||
val result = mutableListOf<Candidate>()
|
||||
var bestGroup = groupNumbers.first()
|
||||
for ((index, candidate) in candidates.withIndex()) {
|
||||
val group = groupNumbers[index]
|
||||
if (bestGroup > group) {
|
||||
bestGroup = group
|
||||
result.clear()
|
||||
}
|
||||
if (bestGroup == group) {
|
||||
result.add(candidate)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun isSuccess(): Boolean {
|
||||
return currentApplicability == CandidateApplicability.RESOLVED
|
||||
}
|
||||
}
|
||||
|
||||
// Collects properties that potentially could be invoke receivers, like 'propertyName()',
|
||||
// and initiates further invoke resolution by adding property-bound invoke consumers
|
||||
class InvokeReceiverCandidateCollector(
|
||||
val callResolver: CallResolver,
|
||||
val invokeCallInfo: CallInfo,
|
||||
components: InferenceComponents,
|
||||
val invokeConsumer: AccumulatingTowerDataConsumer
|
||||
) : CandidateCollector(components) {
|
||||
override fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
|
||||
val applicability = super.consumeCandidate(group, candidate)
|
||||
|
||||
if (applicability >= CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
|
||||
val session = components.session
|
||||
val boundInvokeCallInfo = CallInfo(
|
||||
invokeCallInfo.callKind,
|
||||
FirQualifiedAccessExpressionImpl(session, null, false).apply {
|
||||
calleeReference = FirNamedReferenceWithCandidate(
|
||||
session,
|
||||
null,
|
||||
(candidate.symbol as ConeCallableSymbol).callableId.callableName,
|
||||
candidate
|
||||
)
|
||||
typeRef = callResolver.typeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe())
|
||||
},
|
||||
invokeCallInfo.arguments,
|
||||
invokeCallInfo.isSafeCall,
|
||||
invokeCallInfo.typeArguments,
|
||||
session,
|
||||
invokeCallInfo.containingFile,
|
||||
invokeCallInfo.container,
|
||||
invokeCallInfo.typeProvider
|
||||
)
|
||||
|
||||
invokeConsumer.addConsumer(
|
||||
createSimpleFunctionConsumer(
|
||||
session, OperatorNameConventions.INVOKE,
|
||||
boundInvokeCallInfo, components, callResolver.collector
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return applicability
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import kotlin.coroutines.Continuation
|
||||
|
||||
interface CheckerSink {
|
||||
fun reportApplicability(new: CandidateApplicability)
|
||||
suspend fun yield()
|
||||
suspend fun yieldApplicability(new: CandidateApplicability) {
|
||||
reportApplicability(new)
|
||||
yield()
|
||||
}
|
||||
|
||||
val components: InferenceComponents
|
||||
|
||||
suspend fun yieldIfNeed()
|
||||
}
|
||||
|
||||
class CheckerSinkImpl(override val components: InferenceComponents, var continuation: Continuation<Unit>? = null) : CheckerSink {
|
||||
var current = CandidateApplicability.RESOLVED
|
||||
override fun reportApplicability(new: CandidateApplicability) {
|
||||
if (new < current) current = new
|
||||
}
|
||||
|
||||
override suspend fun yield() = kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn<Unit> {
|
||||
continuation = it
|
||||
kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
override suspend fun yieldIfNeed() {
|
||||
if (current < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
yield()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun createVariableAndObjectConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector
|
||||
): TowerDataConsumer {
|
||||
return PrioritizedTowerDataConsumer(
|
||||
resultCollector,
|
||||
createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Properties,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
),
|
||||
createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Objects,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun createSimpleFunctionConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector
|
||||
): TowerDataConsumer {
|
||||
return createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Functions,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
)
|
||||
}
|
||||
|
||||
fun createFunctionConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector,
|
||||
callResolver: CallResolver
|
||||
): TowerDataConsumer {
|
||||
val varCallInfo = CallInfo(
|
||||
CallKind.VariableAccess,
|
||||
callInfo.explicitReceiver,
|
||||
emptyList(),
|
||||
callInfo.isSafeCall,
|
||||
callInfo.typeArguments,
|
||||
inferenceComponents.session,
|
||||
callInfo.containingFile,
|
||||
callInfo.container,
|
||||
callInfo.typeProvider
|
||||
)
|
||||
return PrioritizedTowerDataConsumer(
|
||||
resultCollector,
|
||||
createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Functions,
|
||||
callInfo,
|
||||
inferenceComponents,
|
||||
resultCollector
|
||||
),
|
||||
AccumulatingTowerDataConsumer(resultCollector).apply {
|
||||
initialConsumer = createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Properties,
|
||||
varCallInfo,
|
||||
inferenceComponents,
|
||||
InvokeReceiverCandidateCollector(
|
||||
callResolver,
|
||||
invokeCallInfo = callInfo,
|
||||
components = inferenceComponents,
|
||||
invokeConsumer = this
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun createSimpleConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
token: TowerScopeLevel.Token<*>,
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents,
|
||||
resultCollector: CandidateCollector
|
||||
): TowerDataConsumer {
|
||||
val factory = CandidateFactory(inferenceComponents, callInfo)
|
||||
val explicitReceiver = callInfo.explicitReceiver
|
||||
return if (explicitReceiver != null) {
|
||||
val receiverValue = ExpressionReceiverValue(explicitReceiver, callInfo.typeProvider)
|
||||
if (explicitReceiver is FirResolvedQualifier) {
|
||||
val qualified =
|
||||
QualifiedReceiverTowerDataConsumer(session, name, token, receiverValue, factory, resultCollector)
|
||||
|
||||
if (explicitReceiver.classId != null) {
|
||||
PrioritizedTowerDataConsumer(
|
||||
resultCollector,
|
||||
qualified,
|
||||
ExplicitReceiverTowerDataConsumer(session, name, token, receiverValue, factory, resultCollector)
|
||||
)
|
||||
} else {
|
||||
qualified
|
||||
}
|
||||
|
||||
} else {
|
||||
ExplicitReceiverTowerDataConsumer(session, name, token, receiverValue, factory, resultCollector)
|
||||
}
|
||||
} else {
|
||||
NoExplicitReceiverTowerDataConsumer(session, name, token, factory, resultCollector)
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,6 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal sealed class CheckReceivers : ResolutionStage() {
|
||||
@@ -141,7 +140,6 @@ internal object MapArguments : ResolutionStage() {
|
||||
return sink.yieldApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal object CheckArguments : CheckerStage() {
|
||||
@@ -171,11 +169,9 @@ internal object DiscriminateSynthetics : CheckerStage() {
|
||||
sink.reportApplicability(CandidateApplicability.SYNTHETIC_RESOLVED)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal object CheckVisibility : CheckerStage() {
|
||||
|
||||
private fun ConeSymbol.packageFqName(): FqName {
|
||||
return when (this) {
|
||||
is ConeClassLikeSymbol -> classId.packageFqName
|
||||
@@ -214,20 +210,4 @@ internal object CheckVisibility : CheckerStage() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun functionCallResolutionSequence() = listOf(
|
||||
CheckVisibility, MapArguments, CheckExplicitReceiverConsistency, CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch, CheckReceivers.Extension, CheckArguments
|
||||
)
|
||||
|
||||
|
||||
internal fun qualifiedAccessResolutionSequence() = listOf(
|
||||
CheckVisibility,
|
||||
DiscriminateSynthetics,
|
||||
CheckExplicitReceiverConsistency,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension
|
||||
)
|
||||
}
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.constructClassType
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassType
|
||||
import org.jetbrains.kotlin.fir.types.ConeStarProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
abstract class TowerDataConsumer {
|
||||
abstract fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
// resultCollector: CandidateCollector,
|
||||
group: Int
|
||||
): ProcessorAction
|
||||
|
||||
private var stopGroup = Int.MAX_VALUE
|
||||
fun skipGroup(group: Int, resultCollector: CandidateCollector): Boolean {
|
||||
if (resultCollector.isSuccess() && stopGroup == Int.MAX_VALUE) {
|
||||
stopGroup = group
|
||||
}
|
||||
if (group >= stopGroup) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class QualifiedReceiverTowerDataConsumer<T : FirBasedSymbol<*>>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val explicitReceiver: ExpressionReceiverValue,
|
||||
val candidateFactory: CandidateFactory,
|
||||
val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
if (kind != TowerDataKind.EMPTY) return ProcessorAction.NEXT
|
||||
|
||||
return QualifiedReceiverTowerLevel(session).processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver,
|
||||
processor = TowerLevelProcessorImpl(group)
|
||||
)
|
||||
}
|
||||
|
||||
private inner class TowerLevelProcessorImpl(val group: Int) : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
assert(dispatchReceiverValue == null)
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = null,
|
||||
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PrioritizedTowerDataConsumer(
|
||||
val resultCollector: CandidateCollector,
|
||||
vararg val consumers: TowerDataConsumer
|
||||
) : TowerDataConsumer() {
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
for ((index, consumer) in consumers.withIndex()) {
|
||||
val action = consumer.consume(kind, towerScopeLevel, group * consumers.size + index)
|
||||
if (action.stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
// Yet is used exclusively for invokes:
|
||||
// - initialConsumer consumes property which is invoke receiver
|
||||
// - additionalConsumers consume invoke calls themselves
|
||||
class AccumulatingTowerDataConsumer(
|
||||
private val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
lateinit var initialConsumer: TowerDataConsumer
|
||||
private val additionalConsumers = mutableListOf<TowerDataConsumer>()
|
||||
|
||||
private data class TowerData(val kind: TowerDataKind, val level: TowerScopeLevel, val group: Int)
|
||||
|
||||
private val accumulatedTowerData = mutableListOf<TowerData>()
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
accumulatedTowerData += TowerData(kind, towerScopeLevel, group)
|
||||
|
||||
if (initialConsumer.consume(kind, towerScopeLevel, group).stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
for (consumer in additionalConsumers) {
|
||||
val action = consumer.consume(kind, towerScopeLevel, group)
|
||||
if (action.stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
fun addConsumer(consumer: TowerDataConsumer): ProcessorAction {
|
||||
additionalConsumers += consumer
|
||||
for ((kind, level, group) in accumulatedTowerData) {
|
||||
if (consumer.consume(kind, level, group).stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
class ExplicitReceiverTowerDataConsumer<T : FirBasedSymbol<*>>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val explicitReceiver: ExpressionReceiverValue,
|
||||
val candidateFactory: CandidateFactory,
|
||||
val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
companion object {
|
||||
val defaultPackage = Name.identifier("kotlin")
|
||||
}
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
return when (kind) {
|
||||
TowerDataKind.EMPTY ->
|
||||
MemberScopeTowerLevel(session, explicitReceiver, scopeSession = candidateFactory.inferenceComponents.scopeSession)
|
||||
.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver = null,
|
||||
processor = EmptyKindTowerProcessor(group)
|
||||
)
|
||||
TowerDataKind.TOWER_LEVEL -> {
|
||||
if (token == TowerScopeLevel.Token.Objects) return ProcessorAction.NEXT
|
||||
towerScopeLevel.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver = explicitReceiver,
|
||||
processor = TowerLevelKindTowerProcessor(group)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private inner class EmptyKindTowerProcessor(val group: Int) : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
implicitExtensionReceiverValue,
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
private inner class TowerLevelKindTowerProcessor(val group: Int) : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
if (symbol is FirNamedFunctionSymbol && symbol.callableId.packageName.startsWith(defaultPackage)) {
|
||||
val explicitReceiverType = explicitReceiver.type
|
||||
if (dispatchReceiverValue == null && explicitReceiverType is ConeClassType) {
|
||||
val declarationReceiverTypeRef =
|
||||
(symbol as? FirCallableSymbol<*>)?.fir?.receiverTypeRef as? FirResolvedTypeRef
|
||||
val declarationReceiverType = declarationReceiverTypeRef?.type
|
||||
if (declarationReceiverType is ConeClassType) {
|
||||
if (!AbstractTypeChecker.isSubtypeOf(
|
||||
candidateFactory.inferenceComponents.ctx,
|
||||
explicitReceiverType,
|
||||
declarationReceiverType.lookupTag.constructClassType(
|
||||
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(),
|
||||
isNullable = true
|
||||
)
|
||||
)
|
||||
) {
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val candidate = candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
implicitExtensionReceiverValue,
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidate
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NoExplicitReceiverTowerDataConsumer<T : FirBasedSymbol<*>>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val candidateFactory: CandidateFactory,
|
||||
val resultCollector: CandidateCollector
|
||||
) : TowerDataConsumer() {
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (skipGroup(group, resultCollector)) return ProcessorAction.NEXT
|
||||
return when (kind) {
|
||||
|
||||
TowerDataKind.TOWER_LEVEL -> {
|
||||
towerScopeLevel.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
explicitReceiver = null,
|
||||
processor = TowerLevelProcessorImpl(group)
|
||||
)
|
||||
}
|
||||
else -> ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
private inner class TowerLevelProcessorImpl(val group: Int) : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
implicitExtensionReceiverValue,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirImportImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
|
||||
import org.jetbrains.kotlin.fir.scopes.processClassifiersByNameWithAction
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
interface TowerScopeLevel {
|
||||
|
||||
sealed class Token<out T : FirBasedSymbol<*>> {
|
||||
object Properties : Token<FirPropertySymbol>()
|
||||
|
||||
object Functions : Token<FirFunctionSymbol<*>>()
|
||||
object Objects : Token<FirBasedSymbol<*>>()
|
||||
}
|
||||
|
||||
fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction
|
||||
|
||||
interface TowerScopeLevelProcessor<T : ConeSymbol> {
|
||||
fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
implicitExtensionReceiverValue: ImplicitReceiverValue?
|
||||
): ProcessorAction
|
||||
}
|
||||
|
||||
object Empty : TowerScopeLevel {
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction = ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SessionBasedTowerLevel(val session: FirSession) : TowerScopeLevel {
|
||||
protected fun FirBasedSymbol<*>.dispatchReceiverValue(): ClassDispatchReceiverValue? {
|
||||
return when (this) {
|
||||
is FirNamedFunctionSymbol -> fir.dispatchReceiverValue(session)
|
||||
is FirClassSymbol -> ClassDispatchReceiverValue(fir.symbol)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
protected fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(extensionReceiver: ReceiverValue?): Boolean {
|
||||
val hasExtensionReceiver = hasExtensionReceiver()
|
||||
return hasExtensionReceiver == (extensionReceiver != null)
|
||||
}
|
||||
}
|
||||
|
||||
// This is more like "dispatch receiver-based tower level"
|
||||
// Here we always have an explicit or implicit dispatch receiver, and can access members of its scope
|
||||
// (which is separated from currently accessible scope, see below)
|
||||
// So: dispatch receiver = given explicit or implicit receiver (always present)
|
||||
// So: extension receiver = either none, if dispatch receiver = explicit receiver,
|
||||
// or given implicit or explicit receiver, otherwise
|
||||
class MemberScopeTowerLevel(
|
||||
session: FirSession,
|
||||
val dispatchReceiver: ReceiverValue,
|
||||
val implicitExtensionReceiver: ImplicitReceiverValue? = null,
|
||||
val scopeSession: ScopeSession
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
private fun <T : FirBasedSymbol<*>> processMembers(
|
||||
output: TowerScopeLevel.TowerScopeLevelProcessor<T>,
|
||||
explicitExtensionReceiver: ExpressionReceiverValue?,
|
||||
processScopeMembers: FirScope.(processor: (T) -> ProcessorAction) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
if (implicitExtensionReceiver != null && explicitExtensionReceiver != null) return ProcessorAction.NEXT
|
||||
val extensionReceiver = implicitExtensionReceiver ?: explicitExtensionReceiver
|
||||
val scope = dispatchReceiver.type.scope(session, scopeSession) ?: return ProcessorAction.NEXT
|
||||
if (scope.processScopeMembers { candidate ->
|
||||
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(extensionReceiver)) {
|
||||
// NB: we do not check dispatchReceiverValue != null here,
|
||||
// because of objects & constructors (see comments in dispatchReceiverValue() implementation)
|
||||
output.consumeCandidate(candidate, candidate.dispatchReceiverValue(), implicitExtensionReceiver)
|
||||
} else if (candidate is FirClassLikeSymbol<*>) {
|
||||
output.consumeCandidate(candidate, null, implicitExtensionReceiver)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}.stop()
|
||||
) return ProcessorAction.STOP
|
||||
val withSynthetic = FirSyntheticPropertiesScope(session, scope, ReturnTypeCalculatorWithJump(session, scopeSession))
|
||||
return withSynthetic.processScopeMembers { symbol ->
|
||||
output.consumeCandidate(symbol, symbol.dispatchReceiverValue(), implicitExtensionReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
val explicitExtensionReceiver = if (dispatchReceiver == explicitReceiver) null else explicitReceiver
|
||||
return when (token) {
|
||||
TowerScopeLevel.Token.Properties -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processPropertiesByName(name, symbol.cast())
|
||||
}
|
||||
TowerScopeLevel.Token.Functions -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processFunctionsByName(name, symbol.cast())
|
||||
}
|
||||
TowerScopeLevel.Token.Objects -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processClassifiersByNameWithAction(name, FirPosition.OTHER, symbol.cast())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is more like "scope-based tower level"
|
||||
// We can access here members of currently accessible scope which is not influenced by explicit receiver
|
||||
// We can either have no explicit receiver at all, or it can be an extension receiver
|
||||
// An explicit receiver never can be a dispatch receiver at this level
|
||||
// So: dispatch receiver = strictly NONE
|
||||
// So: extension receiver = either none or explicit
|
||||
// (if explicit receiver exists, it always *should* be an extension receiver)
|
||||
class ScopeTowerLevel(
|
||||
session: FirSession,
|
||||
val scope: FirScope,
|
||||
val implicitExtensionReceiver: ImplicitReceiverValue? = null
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
if (explicitReceiver != null && implicitExtensionReceiver != null) {
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
val extensionReceiver = explicitReceiver ?: implicitExtensionReceiver
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (token) {
|
||||
TowerScopeLevel.Token.Properties -> scope.processPropertiesByName(name) { candidate ->
|
||||
if (candidate.hasConsistentExtensionReceiver(extensionReceiver) && candidate.dispatchReceiverValue() == null) {
|
||||
processor.consumeCandidate(
|
||||
candidate as T, dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = implicitExtensionReceiver
|
||||
)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
TowerScopeLevel.Token.Functions -> scope.processFunctionsByName(name) { candidate ->
|
||||
if (candidate.hasConsistentExtensionReceiver(extensionReceiver) && candidate.dispatchReceiverValue() == null) {
|
||||
processor.consumeCandidate(
|
||||
candidate as T, dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = implicitExtensionReceiver
|
||||
)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
TowerScopeLevel.Token.Objects -> scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
|
||||
processor.consumeCandidate(
|
||||
it as T, dispatchReceiverValue = null,
|
||||
implicitExtensionReceiverValue = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles only statics and top-levels, DOES NOT handle objects/companions members
|
||||
*/
|
||||
class QualifiedReceiverTowerLevel(session: FirSession) : SessionBasedTowerLevel(session) {
|
||||
override fun <T : FirBasedSymbol<*>> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
val qualifiedReceiver = explicitReceiver?.explicitReceiverExpression as FirResolvedQualifier
|
||||
val scope = FirExplicitSimpleImportingScope(
|
||||
listOf(
|
||||
FirResolvedImportImpl(
|
||||
session,
|
||||
FirImportImpl(session, null, FqName.topLevel(name), false, null),
|
||||
qualifiedReceiver.packageFqName,
|
||||
qualifiedReceiver.relativeClassFqName
|
||||
)
|
||||
), session
|
||||
)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return if (token == TowerScopeLevel.Token.Objects) {
|
||||
scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
|
||||
processor.consumeCandidate(it as T, null, null)
|
||||
}
|
||||
} else {
|
||||
scope.processCallables(name, token.cast()) {
|
||||
val fir = it.fir
|
||||
if (fir is FirCallableMemberDeclaration<*> && fir.isStatic || it.callableId.classId == null) {
|
||||
processor.consumeCandidate(it as T, null, null)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirCallableDeclaration<*>.dispatchReceiverValue(session: FirSession): ClassDispatchReceiverValue? {
|
||||
// TODO: this is not true at least for inner class constructors
|
||||
if (this is FirConstructor) return null
|
||||
val id = (this.symbol as ConeCallableSymbol).callableId.classId ?: return null
|
||||
val symbol = session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(id) as? FirClassSymbol ?: return null
|
||||
val regularClass = symbol.fir
|
||||
|
||||
// TODO: this is also not true, but objects can be also imported
|
||||
if (regularClass.classKind == ClassKind.OBJECT) return null
|
||||
|
||||
return ClassDispatchReceiverValue(regularClass.symbol)
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.hasExtensionReceiver(): Boolean = this.fir.receiverTypeRef != null
|
||||
Reference in New Issue
Block a user