FIR: Implement basic function call resolve
This commit is contained in:
+68
-74
@@ -36,6 +36,13 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
return (element.transformChildren(this, data) as E).compose()
|
return (element.transformChildren(this, data) as E).compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult<FirFile> {
|
||||||
|
return withScopeCleanup {
|
||||||
|
scopes += FirTopLevelDeclaredMemberScope(file, session)
|
||||||
|
super.transformFile(file, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: Any?): CompositeTransformResult<FirTypeRef> {
|
override fun transformImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: Any?): CompositeTransformResult<FirTypeRef> {
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return implicitTypeRef.compose()
|
return implicitTypeRef.compose()
|
||||||
@@ -102,6 +109,7 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val scopes = mutableListOf<FirScope>()
|
val scopes = mutableListOf<FirScope>()
|
||||||
|
val localScopes = mutableListOf<FirScope>()
|
||||||
|
|
||||||
enum class CandidateApplicability {
|
enum class CandidateApplicability {
|
||||||
HIDDEN,
|
HIDDEN,
|
||||||
@@ -112,8 +120,8 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
|
|
||||||
inner class ApplicabilityChecker {
|
inner class ApplicabilityChecker {
|
||||||
|
|
||||||
var groupCounter = 0
|
private var groupCounter = 0
|
||||||
val groupNumbers = mutableListOf<Int>()
|
private val groupNumbers = mutableListOf<Int>()
|
||||||
val candidates = mutableListOf<ConeCallableSymbol>()
|
val candidates = mutableListOf<ConeCallableSymbol>()
|
||||||
|
|
||||||
|
|
||||||
@@ -122,6 +130,7 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
|
|
||||||
var expectedType: FirTypeRef? = null
|
var expectedType: FirTypeRef? = null
|
||||||
var explicitReceiverType: FirTypeRef? = null
|
var explicitReceiverType: FirTypeRef? = null
|
||||||
|
var parameterCount = 0
|
||||||
|
|
||||||
fun newDataSet() {
|
fun newDataSet() {
|
||||||
groupNumbers.clear()
|
groupNumbers.clear()
|
||||||
@@ -144,10 +153,17 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
|
|
||||||
|
|
||||||
private fun getApplicability(symbol: ConeCallableSymbol): CandidateApplicability {
|
private fun getApplicability(symbol: ConeCallableSymbol): CandidateApplicability {
|
||||||
val declaration = (symbol as? FirBasedSymbol<FirCallableMember>)?.fir
|
val declaration = (symbol as? FirBasedSymbol<*>)?.fir
|
||||||
?: return CandidateApplicability.HIDDEN
|
?: return CandidateApplicability.HIDDEN
|
||||||
|
declaration as FirDeclaration
|
||||||
|
|
||||||
|
if (declaration is FirFunction) {
|
||||||
|
if (declaration.valueParameters.size != parameterCount) return CandidateApplicability.PARAMETER_MAPPING_ERROR
|
||||||
|
}
|
||||||
|
if (declaration is FirCallableMember) {
|
||||||
|
if ((declaration.receiverTypeRef == null) != (explicitReceiverType == null)) return CandidateApplicability.PARAMETER_MAPPING_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
if (!isSubtypeOf(declaration.receiverTypeRef, explicitReceiverType)) return CandidateApplicability.PARAMETER_MAPPING_ERROR
|
|
||||||
return CandidateApplicability.RESOLVED
|
return CandidateApplicability.RESOLVED
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,47 +184,74 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformQualifiedAccessExpression(
|
|
||||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
private fun <T : FirQualifiedAccess> resolveQualifiedAccess(
|
||||||
data: Any?
|
qualifiedAccess: T,
|
||||||
): CompositeTransformResult<FirStatement> {
|
expectedType: FirTypeRef?,
|
||||||
qualifiedAccessExpression.explicitReceiver?.visitNoTransform(this, null)
|
configure: ApplicabilityChecker.() -> Unit
|
||||||
val callee = qualifiedAccessExpression.calleeReference as? FirNamedReference ?: return qualifiedAccessExpression.compose()
|
): T {
|
||||||
|
qualifiedAccess.explicitReceiver?.visitNoTransform(this, null)
|
||||||
|
val callee = qualifiedAccess.calleeReference as? FirNamedReference ?: return qualifiedAccess
|
||||||
|
|
||||||
with(ApplicabilityChecker()) {
|
with(ApplicabilityChecker()) {
|
||||||
expectedType = data as FirTypeRef?
|
this.expectedType = expectedType
|
||||||
explicitReceiverType = qualifiedAccessExpression.explicitReceiver?.resultType
|
explicitReceiverType = qualifiedAccess.explicitReceiver?.resultType
|
||||||
|
configure()
|
||||||
newDataSet()
|
newDataSet()
|
||||||
|
|
||||||
for (scope in scopes.asReversed()) {
|
for (scope in (scopes + localScopes).asReversed()) {
|
||||||
newGroup()
|
newGroup()
|
||||||
val name = callee.name
|
val name = callee.name
|
||||||
scope.processPropertiesByName(name) {
|
scope.processPropertiesByName(name) {
|
||||||
consumeCandidate(symbol = it)
|
consumeCandidate(symbol = it)
|
||||||
ProcessorAction.NEXT
|
ProcessorAction.NEXT
|
||||||
}
|
}
|
||||||
|
scope.processFunctionsByName(name) {
|
||||||
|
consumeCandidate(symbol = it)
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
if (currentApplicability == CandidateApplicability.RESOLVED) {
|
if (currentApplicability == CandidateApplicability.RESOLVED) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = candidates
|
val result = candidates
|
||||||
qualifiedAccessExpression.transformCalleeReference(this@FirBodyResolveTransformer, result)
|
return qualifiedAccess.transformCalleeReference(this@FirBodyResolveTransformer, result) as T
|
||||||
|
|
||||||
bindingContext[qualifiedAccessExpression] =
|
|
||||||
when (val newCallee = qualifiedAccessExpression.calleeReference) {
|
|
||||||
is FirErrorNamedReference ->
|
|
||||||
FirErrorTypeRefImpl(session, qualifiedAccessExpression.psi, newCallee.errorReason)
|
|
||||||
is FirResolvedCallableReference ->
|
|
||||||
(newCallee.callableSymbol as FirBasedSymbol<FirCallableMember>).fir.returnTypeRef
|
|
||||||
else -> error("WTF!")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return qualifiedAccessExpression.compose()
|
}
|
||||||
|
|
||||||
|
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 ->
|
||||||
|
(newCallee.callableSymbol as FirBasedSymbol<FirCallableMember>).fir.returnTypeRef
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformQualifiedAccessExpression(
|
||||||
|
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||||
|
data: Any?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
val result = resolveQualifiedAccess(qualifiedAccessExpression, data as FirTypeRef?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
storeTypeFromCallee(result)
|
||||||
|
return result.compose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
|
val result = resolveQualifiedAccess(functionCall, data as FirTypeRef?) {
|
||||||
|
parameterCount = functionCall.arguments.size
|
||||||
|
}
|
||||||
|
storeTypeFromCallee(result)
|
||||||
|
return result.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
||||||
if (namedReference is FirResolvedCallableReference) return namedReference.compose()
|
if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
||||||
val name = namedReference.name
|
val name = namedReference.name
|
||||||
val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
||||||
return when (referents.size) {
|
return when (referents.size) {
|
||||||
@@ -225,55 +268,6 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer<Any?>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// override fun transformAssignment(assignment: FirAssignment, data: Any?): CompositeTransformResult<FirStatement> {
|
|
||||||
// return withNewSettings {
|
|
||||||
// lookupProperties = true
|
|
||||||
// lookupFunctions = false
|
|
||||||
// super.transformAssignment(assignment, data)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
//
|
|
||||||
// override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
|
||||||
// if (namedReference is FirResolvedCallableReference) return namedReference.compose()
|
|
||||||
// val name = namedReference.name
|
|
||||||
// val referents = mutableListOf<ConeCallableSymbol>()
|
|
||||||
// fun collect(it: ConeCallableSymbol): ProcessorAction {
|
|
||||||
// referents.add(it)
|
|
||||||
// return ProcessorAction.NEXT
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (lookupFunctions)
|
|
||||||
// towerScope.processFunctionsByName(name, ::collect)
|
|
||||||
// if (lookupProperties)
|
|
||||||
// towerScope.processPropertiesByName(name, ::collect)
|
|
||||||
//
|
|
||||||
// return when (referents.size) {
|
|
||||||
// 0 -> FirErrorNamedReference(
|
|
||||||
// namedReference.session, namedReference.psi, "Unresolved name: $name"
|
|
||||||
// ).compose()
|
|
||||||
// 1 -> FirResolvedCallableReferenceImpl(
|
|
||||||
// namedReference.session, namedReference.psi,
|
|
||||||
// name, referents.single()
|
|
||||||
// ).compose()
|
|
||||||
// else -> FirErrorNamedReference(
|
|
||||||
// namedReference.session, namedReference.psi, "Ambiguity: $name, ${referents.map { it.callableId }}"
|
|
||||||
// ).compose()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun transformQualifiedAccessExpression(
|
|
||||||
// qualifiedAccessExpression: FirQualifiedAccessExpression,
|
|
||||||
// data: Any?
|
|
||||||
// ): CompositeTransformResult<FirStatement> {
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// return super.transformQualifiedAccessExpression(qualifiedAccessExpression, data)
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,22 @@ class Foo {
|
|||||||
val x = 1
|
val x = 1
|
||||||
|
|
||||||
fun abc() = x
|
fun abc() = x
|
||||||
|
|
||||||
|
fun cba() = abc()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
val x = ""
|
||||||
|
|
||||||
|
fun Foo.abc() = x
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Foo.ext() = x
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buz() {
|
||||||
|
bar()
|
||||||
}
|
}
|
||||||
@@ -9,4 +9,27 @@ FILE: access.kt
|
|||||||
return@@@abc R|/Foo.x|
|
return@@@abc R|/Foo.x|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final function cba(): R|kotlin/Int| {
|
||||||
|
return@@@cba R|/Foo.abc|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class Bar {
|
||||||
|
public constructor(): super<R|kotlin/Any|>()
|
||||||
|
|
||||||
|
public final property x(val): R|kotlin/String| = String()
|
||||||
|
public get(): <implicit>
|
||||||
|
|
||||||
|
public final function abc R|Foo|.(): R|kotlin/Int| {
|
||||||
|
return@@@abc R|/Foo.x|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final function ext R|Foo|.(): R|kotlin/Int| {
|
||||||
|
return@@@ext R|/Foo.x|
|
||||||
|
}
|
||||||
|
public final function bar(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final function buz(): R|kotlin/Unit| {
|
||||||
|
R|/bar|()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user