diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index 33011ce54a5..751fbb9224c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -36,6 +36,13 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( return (element.transformChildren(this, data) as E).compose() } + override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult { + return withScopeCleanup { + scopes += FirTopLevelDeclaredMemberScope(file, session) + super.transformFile(file, data) + } + } + override fun transformImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: Any?): CompositeTransformResult { if (data == null) return implicitTypeRef.compose() @@ -102,6 +109,7 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( } val scopes = mutableListOf() + val localScopes = mutableListOf() enum class CandidateApplicability { HIDDEN, @@ -112,8 +120,8 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( inner class ApplicabilityChecker { - var groupCounter = 0 - val groupNumbers = mutableListOf() + private var groupCounter = 0 + private val groupNumbers = mutableListOf() val candidates = mutableListOf() @@ -122,6 +130,7 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( var expectedType: FirTypeRef? = null var explicitReceiverType: FirTypeRef? = null + var parameterCount = 0 fun newDataSet() { groupNumbers.clear() @@ -144,10 +153,17 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( private fun getApplicability(symbol: ConeCallableSymbol): CandidateApplicability { - val declaration = (symbol as? FirBasedSymbol)?.fir + 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 + } + 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 } @@ -168,47 +184,74 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( } } - override fun transformQualifiedAccessExpression( - qualifiedAccessExpression: FirQualifiedAccessExpression, - data: Any? - ): CompositeTransformResult { - qualifiedAccessExpression.explicitReceiver?.visitNoTransform(this, null) - val callee = qualifiedAccessExpression.calleeReference as? FirNamedReference ?: return qualifiedAccessExpression.compose() + + private fun resolveQualifiedAccess( + qualifiedAccess: T, + expectedType: FirTypeRef?, + configure: ApplicabilityChecker.() -> Unit + ): T { + qualifiedAccess.explicitReceiver?.visitNoTransform(this, null) + val callee = qualifiedAccess.calleeReference as? FirNamedReference ?: return qualifiedAccess with(ApplicabilityChecker()) { - expectedType = data as FirTypeRef? - explicitReceiverType = qualifiedAccessExpression.explicitReceiver?.resultType + this.expectedType = expectedType + explicitReceiverType = qualifiedAccess.explicitReceiver?.resultType + configure() newDataSet() - for (scope in scopes.asReversed()) { + for (scope in (scopes + localScopes).asReversed()) { newGroup() val name = callee.name scope.processPropertiesByName(name) { consumeCandidate(symbol = it) ProcessorAction.NEXT } + scope.processFunctionsByName(name) { + consumeCandidate(symbol = it) + ProcessorAction.NEXT + } if (currentApplicability == CandidateApplicability.RESOLVED) { break } } val result = candidates - qualifiedAccessExpression.transformCalleeReference(this@FirBodyResolveTransformer, result) - - bindingContext[qualifiedAccessExpression] = - when (val newCallee = qualifiedAccessExpression.calleeReference) { - is FirErrorNamedReference -> - FirErrorTypeRefImpl(session, qualifiedAccessExpression.psi, newCallee.errorReason) - is FirResolvedCallableReference -> - (newCallee.callableSymbol as FirBasedSymbol).fir.returnTypeRef - else -> error("WTF!") - } + return qualifiedAccess.transformCalleeReference(this@FirBodyResolveTransformer, result) as T } - return qualifiedAccessExpression.compose() + } + + private fun 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).fir.returnTypeRef + else -> return + } + } + + override fun transformQualifiedAccessExpression( + qualifiedAccessExpression: FirQualifiedAccessExpression, + data: Any? + ): CompositeTransformResult { + val result = resolveQualifiedAccess(qualifiedAccessExpression, data as FirTypeRef?) { + + } + storeTypeFromCallee(result) + return result.compose() + } + + override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult { + val result = resolveQualifiedAccess(functionCall, data as FirTypeRef?) { + parameterCount = functionCall.arguments.size + } + storeTypeFromCallee(result) + return result.compose() } override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult { - if (namedReference is FirResolvedCallableReference) return namedReference.compose() + if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose() val name = namedReference.name val referents = data as? List ?: return namedReference.compose() return when (referents.size) { @@ -225,55 +268,6 @@ class FirBodyResolveTransformer(val session: FirSession) : FirTransformer( } } -// -// override fun transformAssignment(assignment: FirAssignment, data: Any?): CompositeTransformResult { -// return withNewSettings { -// lookupProperties = true -// lookupFunctions = false -// super.transformAssignment(assignment, data) -// } -// } - -// -// override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult { -// if (namedReference is FirResolvedCallableReference) return namedReference.compose() -// val name = namedReference.name -// val referents = mutableListOf() -// 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 { -// -// -// -// return super.transformQualifiedAccessExpression(qualifiedAccessExpression, data) -// } - override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult { diff --git a/compiler/fir/resolve/testData/resolve/expresssions/access.kt b/compiler/fir/resolve/testData/resolve/expresssions/access.kt index 70966b37958..fd8446fb268 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/access.kt +++ b/compiler/fir/resolve/testData/resolve/expresssions/access.kt @@ -3,4 +3,22 @@ class Foo { val x = 1 fun abc() = x + + fun cba() = abc() +} + +class Bar { + val x = "" + + fun Foo.abc() = x +} + +fun Foo.ext() = x + +fun bar() { + +} + +fun buz() { + bar() } \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/expresssions/access.txt b/compiler/fir/resolve/testData/resolve/expresssions/access.txt index 488099d7967..5694659564f 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/access.txt +++ b/compiler/fir/resolve/testData/resolve/expresssions/access.txt @@ -9,4 +9,27 @@ FILE: access.kt return@@@abc R|/Foo.x| } + public final function cba(): R|kotlin/Int| { + return@@@cba R|/Foo.abc|() + } + + } + public final class Bar { + public constructor(): super() + + public final property x(val): R|kotlin/String| = String() + public get(): + + 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|() }