FIR: Re-implement call resolver with proper architecture

This commit is contained in:
Simon Ogorodnik
2019-03-18 21:51:51 +03:00
parent 33b44870d6
commit a562f3db3c
3 changed files with 341 additions and 332 deletions
@@ -7,9 +7,8 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.scope
@@ -22,70 +21,294 @@ 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.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractTypeChecker
import java.util.*
import kotlin.collections.LinkedHashSet
import org.jetbrains.kotlin.utils.addToStdlib.cast
class CallResolver(val typeCalculator: ReturnTypeCalculator) {
lateinit var checkers: List<ApplicabilityChecker>
lateinit var scopes: List<FirScope>
class CallInfo(
val variableAccess: Boolean,
val explicitReceiver: FirExpression?,
val argumentCount: Int
) {
private val names = LinkedHashSet<Name>()
private val newNames = mutableSetOf<Name>()
}
fun pushName(name: Name) {
newNames += name
interface CheckerSink {
fun reportApplicability(new: CandidateApplicability)
}
class CheckerSinkImpl : CheckerSink {
var current = CandidateApplicability.RESOLVED
override fun reportApplicability(new: CandidateApplicability) {
if (new < current) current = new
}
}
private abstract class Checker {
abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
}
private object MapArguments : Checker() {
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
if (symbol.firUnsafe<FirFunction>().valueParameters.size != callInfo.argumentCount) {
return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
}
}
fun runTowerResolver(): ApplicabilityChecker? {
processedScopes.clear()
newNames.clear()
names.clear()
}
var successChecker: ApplicabilityChecker? = null
checkers.forEach {
it.initNames(this.names)
class Candidate(val symbol: ConeSymbol) {}
enum class TowerDataKind {
EMPTY,
TOWER_LEVEL
}
interface TowerScopeLevel {
sealed class Token<out T : ConeSymbol> {
object Properties : Token<ConePropertySymbol>()
object Functions : Token<ConeFunctionSymbol>()
object Objects : Token<ConeClassifierSymbol>()
}
fun <T : ConeSymbol> processElementsByName(
token: Token<T>,
name: Name,
extensionReceiver: ReceiverValueWithPossibleTypes?,
processor: TowerScopeLevelProcessor<T>
): ProcessorAction
interface TowerScopeLevelProcessor<T : ConeSymbol> {
fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction
}
object Empty : TowerScopeLevel {
override fun <T : ConeSymbol> processElementsByName(
token: Token<T>,
name: Name,
extensionReceiver: ReceiverValueWithPossibleTypes?,
processor: TowerScopeLevelProcessor<T>
): ProcessorAction = ProcessorAction.NEXT
}
}
interface ReceiverValue {
val type: ConeKotlinType
}
interface ReceiverValueWithPossibleTypes : ReceiverValue
class MemberScopeTowerLevel(
val session: FirSession,
val dispatchReceiver: ReceiverValueWithPossibleTypes
) : TowerScopeLevel {
private fun <T : ConeSymbol> processMembers(
output: TowerScopeLevel.TowerScopeLevelProcessor<T>,
takeMembers: FirScope.(processor: (T) -> ProcessorAction) -> ProcessorAction
): ProcessorAction {
return dispatchReceiver.type.scope(session)?.takeMembers { output.consumeCandidate(it, dispatchReceiver) } ?: ProcessorAction.NEXT
}
override fun <T : ConeSymbol> processElementsByName(
token: TowerScopeLevel.Token<T>,
name: Name,
extensionReceiver: ReceiverValueWithPossibleTypes?,
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
): ProcessorAction {
return when (token) {
TowerScopeLevel.Token.Properties -> processMembers(processor) { this.processPropertiesByName(name, it.cast()) }
TowerScopeLevel.Token.Functions -> processMembers(processor) { this.processFunctionsByName(name, it.cast()) }
TowerScopeLevel.Token.Objects -> ProcessorAction.NEXT
}
}
for ((index, scope) in scopes.asReversed().withIndex()) {
names.addAll(newNames)
newNames.clear()
}
processedScopes.add(scope)
class ScopeTowerLevel(
val session: FirSession,
val scope: FirScope
) : TowerScopeLevel {
override fun <T : ConeSymbol> processElementsByName(
token: TowerScopeLevel.Token<T>,
name: Name,
extensionReceiver: ReceiverValueWithPossibleTypes?,
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
): ProcessorAction {
return when (token) {
names.forEach { name ->
fun process(symbol: ConeSymbol): ProcessorAction {
for (checker in checkers) {
checker.consumeCandidate(index, symbol, this)
TowerScopeLevel.Token.Properties -> scope.processPropertiesByName(name) { processor.consumeCandidate(it as T, null) }
TowerScopeLevel.Token.Functions -> scope.processFunctionsByName(name) { processor.consumeCandidate(it as T, null) }
TowerScopeLevel.Token.Objects -> scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
processor.consumeCandidate(
it as T,
null
)
}
}
}
}
abstract class TowerDataConsumer {
abstract fun consume(
kind: TowerDataKind,
implicitReceiverType: ConeKotlinType?,
towerScopeLevel: TowerScopeLevel,
resultCollector: CandidateCollector
): ProcessorAction
}
fun createVariableConsumer(
session: FirSession,
name: Name,
explicitReceiver: FirExpression?,
explicitReceiverType: FirTypeRef?
): TowerDataConsumer {
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Properties, explicitReceiver, explicitReceiverType)
}
fun createFunctionConsumer(
session: FirSession,
name: Name,
explicitReceiver: FirExpression?,
explicitReceiverType: FirTypeRef?
): TowerDataConsumer {
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Functions, explicitReceiver, explicitReceiverType)
}
fun createSimpleConsumer(
session: FirSession,
name: Name,
token: TowerScopeLevel.Token<*>,
explicitReceiver: FirExpression?,
explicitReceiverType: FirTypeRef?
): TowerDataConsumer {
return if (explicitReceiver != null) {
ExplicitReceiverTowerDataConsumer(session, name, token, object : ReceiverValueWithPossibleTypes {
override val type: ConeKotlinType
get() = explicitReceiverType!!.coneTypeUnsafe()
})
} else {
NoExplicitReceiverTowerDataConsumer(session, name, token)
}
}
class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
val session: FirSession,
val name: Name,
val token: TowerScopeLevel.Token<T>,
val explicitReceiver: ReceiverValueWithPossibleTypes
) : TowerDataConsumer() {
var groupId = 0
override fun consume(
kind: TowerDataKind,
implicitReceiverType: ConeKotlinType?,
towerScopeLevel: TowerScopeLevel,
resultCollector: CandidateCollector
): ProcessorAction {
groupId++
return when (kind) {
TowerDataKind.EMPTY ->
MemberScopeTowerLevel(session, explicitReceiver).processElementsByName(
token,
name,
null,
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
resultCollector.consumeCandidate(groupId, symbol)
return ProcessorAction.NEXT
}
}
return ProcessorAction.NEXT
}
scope.processClassifiersByNameWithAction(name, FirPosition.OTHER, ::process)
scope.processPropertiesByName(name, ::process)
scope.processFunctionsByName(name, ::process)
}
successChecker = checkers.maxBy { it.currentApplicability }
if (successChecker?.currentApplicability == CandidateApplicability.RESOLVED) {
break
}
)
TowerDataKind.TOWER_LEVEL ->
towerScopeLevel.processElementsByName(
token,
name,
explicitReceiver,
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
resultCollector.consumeCandidate(groupId, symbol)
return ProcessorAction.NEXT
}
}
)
}
return successChecker
}
lateinit var session: FirSession
val processedScopes = mutableListOf<FirScope>()
}
class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
val session: FirSession,
val name: Name,
val token: TowerScopeLevel.Token<T>
) : TowerDataConsumer() {
var groupId = 0
override fun consume(
kind: TowerDataKind,
implicitReceiverType: ConeKotlinType?,
towerScopeLevel: TowerScopeLevel,
resultCollector: CandidateCollector
): ProcessorAction {
groupId++
return when (kind) {
TowerDataKind.TOWER_LEVEL -> {
towerScopeLevel.processElementsByName(
token,
name,
null,
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
resultCollector.consumeCandidate(groupId, symbol)
return ProcessorAction.NEXT
}
}
)
}
else -> ProcessorAction.NEXT
}
}
}
class CallResolver(val typeCalculator: ReturnTypeCalculator, val session: FirSession) {
var callInfo: CallInfo? = null
var scopes: List<FirScope>? = null
fun runTowerResolver(towerDataConsumer: TowerDataConsumer): CandidateCollector {
val collector = CandidateCollector(callInfo!!)
towerDataConsumer.consume(TowerDataKind.EMPTY, null, TowerScopeLevel.Empty, collector)
for (scope in scopes!!) {
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, null, ScopeTowerLevel(session, scope), collector)
}
return collector
}
}
@@ -99,9 +322,7 @@ enum class CandidateApplicability {
RESOLVED
}
// TODO: Extract from this transformer
abstract class ApplicabilityChecker {
class CandidateCollector(val callInfo: CallInfo) {
val groupNumbers = mutableListOf<Int>()
val candidates = mutableListOf<ConeSymbol>()
@@ -109,35 +330,27 @@ abstract class ApplicabilityChecker {
var currentApplicability = CandidateApplicability.HIDDEN
var expectedType: FirTypeRef? = null
var explicitReceiverType: FirTypeRef? = null
fun newDataSet() {
groupNumbers.clear()
candidates.clear()
expectedType = null
currentApplicability = CandidateApplicability.HIDDEN
}
protected open fun getApplicability(
protected fun getApplicability(
group: Int,
symbol: ConeSymbol,
resolver: CallResolver
symbol: ConeSymbol
): CandidateApplicability {
val declaration = (symbol as? FirBasedSymbol<*>)?.fir
?: return CandidateApplicability.HIDDEN
declaration as FirDeclaration
if (declaration is FirCallableDeclaration) {
if ((declaration.receiverTypeRef == null) != (explicitReceiverType == null)) return CandidateApplicability.PARAMETER_MAPPING_ERROR
}
val sink = CheckerSinkImpl()
return CandidateApplicability.RESOLVED
MapArguments.check(Candidate(symbol), sink, callInfo)
return sink.current
}
open fun consumeCandidate(group: Int, symbol: ConeSymbol, resolver: CallResolver) {
val applicability = getApplicability(group, symbol, resolver)
fun consumeCandidate(group: Int, symbol: ConeSymbol) {
val applicability = getApplicability(group, symbol)
if (applicability > currentApplicability) {
groupNumbers.clear()
@@ -152,19 +365,13 @@ abstract class ApplicabilityChecker {
}
}
abstract fun initNames(names: LinkedHashSet<Name>)
open fun isSuccessful(index: Int, candidate: ConeSymbol): Boolean {
return true
}
open fun successCandidates(): List<ConeSymbol> {
fun successCandidates(): List<ConeSymbol> {
if (groupNumbers.isEmpty()) return emptyList()
val result = mutableListOf<ConeSymbol>()
var bestGroup = groupNumbers.first()
for ((index, candidate) in candidates.withIndex()) {
val group = groupNumbers[index]
if (!isSuccessful(index, candidate)) continue
if (bestGroup > group) {
bestGroup = group
result.clear()
@@ -177,195 +384,6 @@ abstract class ApplicabilityChecker {
}
}
open class VariableApplicabilityChecker(val name: Name) : ApplicabilityChecker() {
override fun initNames(names: LinkedHashSet<Name>) {
names.add(name)
}
override fun consumeCandidate(group: Int, symbol: ConeSymbol, resolver: CallResolver) {
if (symbol !is ConeVariableSymbol) return
if (symbol.callableId.callableName != name) return
super.consumeCandidate(group, symbol, resolver)
}
}
class VariableInvokeApplicabilityChecker(val variableName: Name) : FunctionApplicabilityChecker(invoke) {
val variableChecker = object : VariableApplicabilityChecker(variableName) {
override fun isSuccessful(index: Int, candidate: ConeSymbol): Boolean {
return matchedProperties[index]
}
}
private var matchedProperties = BitSet()
private var lookupInvoke = false
override fun initNames(names: LinkedHashSet<Name>) {
names.add(variableName)
// if (lookupInvoke) {
// names.add(name)
// }
}
private fun isInvokeApplicableOn(propertySymbol: ConeSymbol, invokeSymbol: ConeCallableSymbol): Boolean {
return true //TODO: Actual type-check here
}
override fun getApplicability(
group: Int,
symbol: ConeSymbol,
resolver: CallResolver
): CandidateApplicability {
symbol as ConeCallableSymbol
val declaration = (symbol as? FirBasedSymbol<*>)?.fir
?: return CandidateApplicability.HIDDEN
declaration as FirDeclaration
if (declaration is FirFunction) {
if (declaration.valueParameters.size != parameterCount) return CandidateApplicability.PARAMETER_MAPPING_ERROR
}
var applicable = false
fun processCandidates(candidates: Iterable<IndexedValue<ConeSymbol>>) {
for ((index, candidate) in candidates) {
val invokeApplicableOn = isInvokeApplicableOn(candidate, symbol)
if (invokeApplicableOn) {
applicable = true
}
matchedProperties[index] = invokeApplicableOn
}
}
if (group == -1) {
processCandidates(listOf(variableChecker.candidates.withIndex().last()))
} else {
processCandidates(variableChecker.candidates.withIndex())
}
if (applicable) {
return CandidateApplicability.RESOLVED
}
return CandidateApplicability.PARAMETER_MAPPING_ERROR
}
private fun checkSuccess(): Boolean {
return currentApplicability == CandidateApplicability.RESOLVED
}
override fun consumeCandidate(group: Int, symbol: ConeSymbol, resolver: CallResolver) {
if (symbol is ConeVariableSymbol && symbol.callableId.callableName == variableName) {
variableChecker.consumeCandidate(group, symbol, resolver)
val lastCandidate = variableChecker.candidates.lastOrNull()
if (variableChecker.currentApplicability == CandidateApplicability.RESOLVED && lastCandidate == symbol) {
val receiverScope =
resolver.typeCalculator.tryCalculateReturnType(lastCandidate.firUnsafe()).type
.scope(resolver.session)
if (!lookupInvoke) resolver.pushName(invoke)
lookupInvoke = true
receiverScope?.processFunctionsByName(invoke) { candidate ->
this.consumeCandidate(-1, candidate, resolver)
ProcessorAction.NEXT
}
if (checkSuccess()) return
for ((index, scope) in resolver.processedScopes.withIndex()) {
scope.processFunctionsByName(invoke) { candidate ->
this.consumeCandidate(index, candidate, resolver)
ProcessorAction.NEXT
}
if (checkSuccess()) return
}
}
}
super.consumeCandidate(group, symbol, resolver)
}
companion object {
val invoke = Name.identifier("invoke")
}
}
class ClassifierApplicabilityChecker(val name: Name) : ApplicabilityChecker() {
override fun initNames(names: LinkedHashSet<Name>) {
names.add(name)
}
override fun consumeCandidate(group: Int, symbol: ConeSymbol, resolver: CallResolver) {
if (symbol !is ConeClassifierSymbol) return
if (symbol.toLookupTag().name != name) return
super.consumeCandidate(group, symbol, resolver)
}
}
open class FunctionApplicabilityChecker(val name: Name) : ApplicabilityChecker() {
var parameterCount = 0
override fun initNames(names: LinkedHashSet<Name>) {
names.add(name)
}
lateinit var session: FirSession
override fun getApplicability(
group: Int,
symbol: ConeSymbol,
resolver: CallResolver
): CandidateApplicability {
val declaration = symbol.firUnsafe<FirCallableDeclaration>()
if (declaration is FirFunction && declaration.valueParameters.size != parameterCount) return CandidateApplicability.PARAMETER_MAPPING_ERROR
var extensionReceiver = declaration.receiverTypeRef?.coneTypeUnsafe()
var dispatchReceiver = declaration.dispatchReceiverType(session)
val explicitReceiverType = explicitReceiverType?.coneTypeUnsafe()
if (explicitReceiverType != null) {
if (dispatchReceiver != null && explicitReceiverType.isSubtypeOf(dispatchReceiver, session)) {
dispatchReceiver = null
}
if (extensionReceiver != null && explicitReceiverType.isSubtypeOf(extensionReceiver, session)) {
extensionReceiver = null
}
if (extensionReceiver != null || dispatchReceiver != null) return CandidateApplicability.WRONG_RECEIVER
}
return CandidateApplicability.RESOLVED
}
fun ConeKotlinType.isSubtypeOf(type: ConeKotlinType, session: FirSession): Boolean {
return try {
AbstractTypeChecker.isSubtypeOf(ConeTypeCheckerContext(true, session), this, type)
} catch (e: IllegalStateException) {
throw RuntimeException("Sub-typing error: subType = ${this.render()}, superType = ${type.render()}", e)
}
}
override fun consumeCandidate(group: Int, symbol: ConeSymbol, resolver: CallResolver) {
if (symbol !is ConeFunctionSymbol) return
if (symbol.callableId.callableName != name) return
session = resolver.session
super.consumeCandidate(group, symbol, resolver)
}
}
fun FirCallableDeclaration.dispatchReceiverType(session: FirSession): ConeKotlinType? {
val id = (this.symbol as ConeCallableSymbol).callableId.classId ?: return null
val symbol = session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(id) as? FirClassSymbol ?: return null
@@ -9,8 +9,6 @@ import com.google.common.collect.LinkedHashMultimap
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
@@ -101,7 +99,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
}
FirOperation.SAFE_AS -> {
bindingContext[resolved] =
resolved.typeRef.withReplacedConeType(
resolved.typeRef.withReplacedConeType(
session,
resolved.typeRef.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE)
)
@@ -130,26 +128,15 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
val jump = ReturnTypeCalculatorWithJump(session)
private fun runTowerResolver(
checkers: List<ApplicabilityChecker>
): ApplicabilityChecker? {
val callResolver = CallResolver(jump)
callResolver.scopes = (scopes + localScopes)
callResolver.checkers = checkers
callResolver.session = session
return callResolver.runTowerResolver()
}
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
bindingContext[access] =
when (val newCallee = access.calleeReference) {
is FirErrorNamedReference ->
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
is FirResolvedCallableReference ->
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
else -> return
}
when (val newCallee = access.calleeReference) {
is FirErrorNamedReference ->
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
is FirResolvedCallableReference ->
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
else -> return
}
}
override fun transformQualifiedAccessExpression(
@@ -170,18 +157,21 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
qualifiedAccessExpression.explicitReceiver?.visitNoTransform(this, null)
val checkers = listOf(VariableApplicabilityChecker(callee.name).apply {
expectedType = data as FirTypeRef?
explicitReceiverType = qualifiedAccessExpression.explicitReceiver?.resultType
})
val receiver = qualifiedAccessExpression.explicitReceiver
val result = runTowerResolver(checkers)
if (result != null) {
val resultExpression = qualifiedAccessExpression.transformCalleeReference(this, result.successCandidates())
storeTypeFromCallee(resultExpression as FirQualifiedAccessExpression)
return resultExpression.compose()
}
return qualifiedAccessExpression.compose()
//val checkers = listOf(VariableApplicabilityChecker(callee.name))
val info = CallInfo(true, receiver, 0)
val resolver = CallResolver(jump, session)
resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed()
val consumer = createVariableConsumer(session, callee.name, qualifiedAccessExpression.explicitReceiver, qualifiedAccessExpression.explicitReceiver?.resultType)
val result = resolver.runTowerResolver(consumer)
val successCandidates = result.successCandidates()
val resultExpression = qualifiedAccessExpression.transformCalleeReference(this, successCandidates)
storeTypeFromCallee(resultExpression as FirQualifiedAccessExpression)
return resultExpression.compose()
}
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult<FirStatement> {
@@ -197,46 +187,47 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
val receiver = functionCall.explicitReceiver
val arguments = functionCall.arguments
val checkers = listOf(FunctionApplicabilityChecker(name).apply {
expectedType = expectedTypeRef
explicitReceiverType = receiver?.resultType
parameterCount = arguments.size
}, VariableInvokeApplicabilityChecker(name).apply {
expectedType = expectedTypeRef
variableChecker.apply {
expectedType = expectedTypeRef
explicitReceiverType = receiver?.resultType
}
parameterCount = arguments.size
})
val info = CallInfo(false, receiver, arguments.size)
val resolver = CallResolver(jump, session)
resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed()
val result = runTowerResolver(checkers)
val resultExpression = when (result) {
is VariableInvokeApplicabilityChecker -> {
FirFunctionCallImpl(functionCall.session, functionCall.psi, safe = functionCall.safe).apply {
calleeReference =
functionCall.calleeReference.transformSingle(this@FirBodyResolveTransformer, result.successCandidates())
explicitReceiver =
FirQualifiedAccessExpressionImpl(
functionCall.session,
functionCall.calleeReference.psi,
functionCall.safe
).apply {
calleeReference = createResolvedNamedReference(
functionCall.calleeReference,
result.variableChecker.successCandidates() as List<ConeCallableSymbol>
)
explicitReceiver = functionCall.explicitReceiver
}
}
}
is ApplicabilityChecker -> {
functionCall.transformCalleeReference(this, result.successCandidates())
}
else -> functionCall
}
val consumer = createFunctionConsumer(session, name, receiver, receiver?.resultType)
val result = resolver.runTowerResolver(consumer)
val successCandidates = result.successCandidates()
// fun isInvoke()
//
// val resultExpression =
//
// when {
// successCandidates.singleOrNull() as? ConeCallableSymbol -> {
// FirFunctionCallImpl(functionCall.session, functionCall.psi, safe = functionCall.safe).apply {
// calleeReference =
// functionCall.calleeReference.transformSingle(this@FirBodyResolveTransformer, result.successCandidates())
// explicitReceiver =
// FirQualifiedAccessExpressionImpl(
// functionCall.session,
// functionCall.calleeReference.psi,
// functionCall.safe
// ).apply {
// calleeReference = createResolvedNamedReference(
// functionCall.calleeReference,
// result.variableChecker.successCandidates() as List<ConeCallableSymbol>
// )
// explicitReceiver = functionCall.explicitReceiver
// }
// }
// }
// is ApplicabilityChecker -> {
// functionCall.transformCalleeReference(this, result.successCandidates())
// }
// else -> functionCall
// }
val resultExpression = functionCall.transformCalleeReference(this, successCandidates)
storeTypeFromCallee(resultExpression as FirFunctionCall)
return resultExpression.compose()
@@ -10,8 +10,8 @@ FILE: dispatchReceiver.kt
public get(): R|Base|
public set(value: R|Base|): R|kotlin/Unit|
public final fun check(): <ERROR TYPE REF: cycle> {
^check R|/My.delegate|.R|/My.check|()
public final fun check(): R|kotlin/Unit| {
^check R|/My.delegate|.R|/Base.check|()
}
}