diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt new file mode 100644 index 00000000000..63daf080b20 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt @@ -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 + + object Function : CallKind() { + override fun sequence(): List { + return functionCallResolutionSequence() + } + } + + object VariableAccess : CallKind() { + override fun sequence(): List { + 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 +) \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt index c918d929194..57b68a39e19 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt @@ -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, - val isSafeCall: Boolean, - - val typeArguments: List, - 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? = null) : CheckerSink { - var current = CandidateApplicability.RESOLVED - override fun reportApplicability(new: CandidateApplicability) { - if (new < current) current = new - } - - override suspend fun yield() = kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn { - 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? = null - val postponedAtoms = mutableListOf() -} - -sealed class CallKind { - abstract fun sequence(): List - - object Function : CallKind() { - override fun sequence(): List { - return functionCallResolutionSequence() - } - } - - object VariableAccess : CallKind() { - override fun sequence(): List { - return qualifiedAccessResolutionSequence() - } - } -} - enum class TowerDataKind { EMPTY, TOWER_LEVEL } -interface TowerScopeLevel { - - sealed class Token> { - object Properties : Token() - - object Functions : Token>() - object Objects : Token>() - } - - fun > processElementsByName( - token: Token, - name: Name, - explicitReceiver: ExpressionReceiverValue?, - processor: TowerScopeLevelProcessor - ): ProcessorAction - - interface TowerScopeLevelProcessor { - fun consumeCandidate( - symbol: T, - dispatchReceiverValue: ClassDispatchReceiverValue?, - implicitExtensionReceiverValue: ImplicitReceiverValue? - ): ProcessorAction - } - - object Empty : TowerScopeLevel { - override fun > processElementsByName( - token: Token, - name: Name, - explicitReceiver: ExpressionReceiverValue?, - processor: TowerScopeLevelProcessor - ): 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 > processMembers( - output: TowerScopeLevel.TowerScopeLevelProcessor, - 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 > processElementsByName( - token: TowerScopeLevel.Token, - name: Name, - explicitReceiver: ExpressionReceiverValue?, - processor: TowerScopeLevel.TowerScopeLevelProcessor - ): 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 > processElementsByName( - token: TowerScopeLevel.Token, - name: Name, - explicitReceiver: ExpressionReceiverValue?, - processor: TowerScopeLevel.TowerScopeLevelProcessor - ): 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 > processElementsByName( - token: TowerScopeLevel.Token, - name: Name, - explicitReceiver: ExpressionReceiverValue?, - processor: TowerScopeLevel.TowerScopeLevelProcessor - ): 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>( - val session: FirSession, - val name: Name, - val token: TowerScopeLevel.Token, - 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 { - 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() - - private data class TowerData(val kind: TowerDataKind, val level: TowerScopeLevel, val group: Int) - - private val accumulatedTowerData = mutableListOf() - - 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>( - val session: FirSession, - val name: Name, - val token: TowerScopeLevel.Token, - 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 { - 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 { - 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>( - val session: FirSession, - val name: Name, - val token: TowerScopeLevel.Token, - 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 { - 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? = 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() - val candidates = mutableListOf() - - - 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 { - override val context: CoroutineContext - get() = EmptyCoroutineContext - - override fun resumeWith(result: Result) { - 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 { - if (groupNumbers.isEmpty()) return emptyList() - if (groupNumbers.size == 1) return candidates - val result = mutableListOf() - 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().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) -} +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt new file mode 100644 index 00000000000..db589627ec8 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -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, + val isSafeCall: Boolean, + + val typeArguments: List, + 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? = null + val postponedAtoms = mutableListOf() +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt new file mode 100644 index 00000000000..f8cdf57390f --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt @@ -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() + val candidates = mutableListOf() + + 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 { + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resumeWith(result: Result) { + 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 { + if (groupNumbers.isEmpty()) return emptyList() + if (groupNumbers.size == 1) return candidates + val result = mutableListOf() + 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 + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CheckerSink.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CheckerSink.kt new file mode 100644 index 00000000000..3533181d4ed --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CheckerSink.kt @@ -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? = null) : CheckerSink { + var current = CandidateApplicability.RESOLVED + override fun reportApplicability(new: CandidateApplicability) { + if (new < current) current = new + } + + override suspend fun yield() = kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn { + continuation = it + kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED + } + + override suspend fun yieldIfNeed() { + if (current < CandidateApplicability.SYNTHETIC_RESOLVED) { + yield() + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConsumerFactories.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConsumerFactories.kt new file mode 100644 index 00000000000..c44b2723920 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConsumerFactories.kt @@ -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) + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt index bbedb18aa4d..f3de11c17fe 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt @@ -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 -) \ No newline at end of file +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerDataConsumers.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerDataConsumers.kt new file mode 100644 index 00000000000..342d659c9cf --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerDataConsumers.kt @@ -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>( + val session: FirSession, + val name: Name, + val token: TowerScopeLevel.Token, + 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 { + 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() + + private data class TowerData(val kind: TowerDataKind, val level: TowerScopeLevel, val group: Int) + + private val accumulatedTowerData = mutableListOf() + + 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>( + val session: FirSession, + val name: Name, + val token: TowerScopeLevel.Token, + 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 { + 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 { + 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>( + val session: FirSession, + val name: Name, + val token: TowerScopeLevel.Token, + 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 { + 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 + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt new file mode 100644 index 00000000000..753d0808c95 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt @@ -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> { + object Properties : Token() + + object Functions : Token>() + object Objects : Token>() + } + + fun > processElementsByName( + token: Token, + name: Name, + explicitReceiver: ExpressionReceiverValue?, + processor: TowerScopeLevelProcessor + ): ProcessorAction + + interface TowerScopeLevelProcessor { + fun consumeCandidate( + symbol: T, + dispatchReceiverValue: ClassDispatchReceiverValue?, + implicitExtensionReceiverValue: ImplicitReceiverValue? + ): ProcessorAction + } + + object Empty : TowerScopeLevel { + override fun > processElementsByName( + token: Token, + name: Name, + explicitReceiver: ExpressionReceiverValue?, + processor: TowerScopeLevelProcessor + ): 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 > processMembers( + output: TowerScopeLevel.TowerScopeLevelProcessor, + 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 > processElementsByName( + token: TowerScopeLevel.Token, + name: Name, + explicitReceiver: ExpressionReceiverValue?, + processor: TowerScopeLevel.TowerScopeLevelProcessor + ): 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 > processElementsByName( + token: TowerScopeLevel.Token, + name: Name, + explicitReceiver: ExpressionReceiverValue?, + processor: TowerScopeLevel.TowerScopeLevelProcessor + ): 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 > processElementsByName( + token: TowerScopeLevel.Token, + name: Name, + explicitReceiver: ExpressionReceiverValue?, + processor: TowerScopeLevel.TowerScopeLevelProcessor + ): 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().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 \ No newline at end of file