diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirNamedReferenceWithCandidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirNamedReferenceWithCandidate.kt index 6a30fe5fa6c..b8764f2b10d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirNamedReferenceWithCandidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirNamedReferenceWithCandidate.kt @@ -7,8 +7,12 @@ package org.jetbrains.kotlin.fir.resolve.calls import com.intellij.psi.PsiElement import org.jetbrains.kotlin.fir.* -import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl +import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference +import org.jetbrains.kotlin.fir.symbols.ConeSymbol import org.jetbrains.kotlin.name.Name class FirNamedReferenceWithCandidate(session: FirSession, psi: PsiElement?, name: Name, val candidate: Candidate) : - FirResolvedCallableReferenceImpl(session, psi, name, candidate.symbol) \ No newline at end of file + FirSimpleNamedReference(session, psi, name) { + override val candidateSymbol: ConeSymbol + get() = candidate.symbol +} \ No newline at end of file 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 c4fb20ec03d..03665fd8935 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 @@ -26,10 +26,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType import org.jetbrains.kotlin.fir.symbols.* -import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.* import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult @@ -204,39 +201,51 @@ open class FirBodyResolveTransformer( access.resultType = typeFromCallee(access) } + private fun typeFromSymbol(symbol: ConeSymbol, makeNullable: Boolean): FirResolvedTypeRef { + return when (symbol) { + is FirCallableSymbol<*> -> { + val returnType = jump.tryCalculateReturnType(symbol.fir) + if (makeNullable) { + returnType.withReplacedConeType( + session, + returnType.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE) + ) + } else { + returnType + } + } + is ConeClassifierSymbol -> { + val fir = (symbol as? FirBasedSymbol<*>)?.fir + // TODO: unhack + if (fir is FirEnumEntry) { + (fir.superTypeRefs.firstOrNull() as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl( + session, + null, + "no enum item supertype" + ) + } else + FirResolvedTypeRefImpl( + session, null, symbol.constructType(emptyArray(), isNullable = false), + annotations = emptyList() + ) + } + else -> error("WTF ! $symbol") + } + } + private fun typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess { + val makeNullable: Boolean by lazy { + access.safe && access.explicitReceiver!!.resultType.coneTypeUnsafe().isNullable + } + return when (val newCallee = access.calleeReference) { is FirErrorNamedReference -> FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason) + is FirNamedReferenceWithCandidate -> { + typeFromSymbol(newCallee.candidateSymbol, makeNullable) + } is FirResolvedCallableReference -> { - val symbol = newCallee.coneSymbol - if (symbol is FirCallableSymbol<*>) { - val returnType = jump.tryCalculateReturnType(symbol.fir) - if (access.safe && access.explicitReceiver!!.resultType.coneTypeUnsafe().isNullable) { - returnType.withReplacedConeType( - session, - returnType.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE) - ) - } else { - returnType - } - } else if (symbol is ConeClassifierSymbol && symbol is FirBasedSymbol<*>) { - val fir = symbol.fir - // TODO: unhack - if (fir is FirEnumEntry) { - (fir.superTypeRefs.firstOrNull() as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl( - session, - null, - "no enum item supertype" - ) - } else - FirResolvedTypeRefImpl( - session, null, symbol.constructType(emptyArray(), isNullable = false), - annotations = emptyList() - ) - } else { - error("WTF ! $symbol") - } + typeFromSymbol(newCallee.coneSymbol, makeNullable) } is FirThisReference -> { val labelName = newCallee.labelName @@ -358,12 +367,14 @@ open class FirBodyResolveTransformer( tryResolveAsQualifier()?.let { return it } } - if (nameReference is FirResolvedCallableReference) { - val symbol = nameReference.coneSymbol as? ConeClassLikeSymbol - if (symbol != null) { - return FirResolvedQualifierImpl(session, nameReference.psi, symbol.classId).apply { - resultType = typeForQualifier(this) - } + val referencedSymbol = when (nameReference) { + is FirResolvedCallableReference -> nameReference.coneSymbol + is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol + else -> null + } + if (referencedSymbol is ConeClassLikeSymbol) { + return FirResolvedQualifierImpl(session, nameReference.psi, referencedSymbol.classId).apply { + resultType = typeForQualifier(this) } } @@ -747,7 +758,13 @@ open class FirBodyResolveTransformer( val expectedTypeRef = data as FirTypeRef? val completeInference = try { + val initialExplicitReceiver = functionCall.explicitReceiver val resultExpression = resolveCallAndSelectCandidate(functionCall, expectedTypeRef) + val resultExplicitReceiver = resultExpression.explicitReceiver + if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccess) { + // name.invoke() case + completeTypeInference(resultExplicitReceiver, null) + } completeTypeInference(resultExpression, expectedTypeRef) } catch (e: Throwable) { throw RuntimeException("While resolving call ${functionCall.render()}", e) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt index 251849e23d5..9eaf9ea3237 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt @@ -42,7 +42,7 @@ class FirCallCompleterTransformer( qualifiedAccessExpression.calleeReference as? FirNamedReferenceWithCandidate ?: return qualifiedAccessExpression.compose() calleeReference.candidate.substitutor - val typeRef = typeCalculator.tryCalculateReturnType(calleeReference.coneSymbol.firUnsafe()) + val typeRef = typeCalculator.tryCalculateReturnType(calleeReference.candidateSymbol.firUnsafe()) val initialType = calleeReference.candidate.substitutor.substituteOrNull(typeRef.type) val finalType = finalSubstitutor.substituteOrNull(initialType) @@ -56,7 +56,7 @@ class FirCallCompleterTransformer( calleeReference.session, calleeReference.psi, calleeReference.name, - calleeReference.coneSymbol + calleeReference.candidateSymbol ) ).compose() } @@ -73,7 +73,7 @@ class FirCallCompleterTransformer( calleeReference.session, calleeReference.psi, calleeReference.name, - calleeReference.coneSymbol + calleeReference.candidateSymbol ) ).compose() } @@ -123,7 +123,7 @@ class FirCallCompleterTransformer( calleeReference.session, calleeReference.psi, calleeReference.name, - calleeReference.coneSymbol + calleeReference.candidateSymbol ) ).compose() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt index 64260ec2a04..39478a1be11 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt @@ -79,6 +79,13 @@ internal object StoreCalleeReference : FirTransformer { + return data.compose() + } + override fun transformResolvedCallableReference( resolvedCallableReference: FirResolvedCallableReference, data: FirResolvedCallableReference diff --git a/compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.kt b/compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.kt new file mode 100644 index 00000000000..05eafc67ce8 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.kt @@ -0,0 +1,11 @@ +class Foo(name: () -> String) { + val result = run { name() } + + val name = result.length +} + +fun bar(name: () -> String) { + val result = run { name() } + + val name = result.length +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.txt b/compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.txt new file mode 100644 index 00000000000..64f48758762 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.txt @@ -0,0 +1,23 @@ +FILE: recursiveBug.kt + public final class Foo : R|kotlin/Any| { + public constructor(name: R|kotlin/Function0|): R|Foo| { + super() + } + + public final val result: R|kotlin/String| = R|kotlin/run|( = run@fun (): R|kotlin/String| { + R|/name|.R|FakeOverride|() + } + ) + public get(): R|kotlin/String| + + public final val name: R|kotlin/Int| = R|/Foo.result|.R|kotlin/String.length| + public get(): R|kotlin/Int| + + } + public final fun bar(name: R|kotlin/Function0|): R|kotlin/Unit| { + lval result: R|kotlin/String| = R|kotlin/run|( = run@fun (): R|kotlin/String| { + R|/name|.R|FakeOverride|() + } + ) + lval name: R|kotlin/Int| = R|/result|.R|kotlin/String.length| + } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt b/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt index 47819e17fcd..41b08c9b743 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt @@ -13,7 +13,7 @@ FILE: topLevelResolve.kt lval setAndList: R|kotlin/collections/Set| = R|kotlin/collections/setOf|(Int(0)).R|kotlin/collections/plus|(R|kotlin/collections/listOf|(Int(1), Int(2))) lval stringAndList: R|kotlin/String| = String().R|kotlin/String.plus|(R|kotlin/collections/emptyList|()) lval map: R|kotlin/collections/Map| = R|kotlin/collections/mapOf|(String().R|kotlin/to|(Int(1)), String(.).R|kotlin/to|(Int(2))).R|kotlin/collections/plus|(String(..).R|kotlin/to|(Int(3))) - lval mapAndMap: = #(String(-).R|kotlin/to|(Int(4))).#(#(String(_).R|kotlin/to|(Int(5)))) + lval mapAndMap: = #(String(-).R?C|kotlin/to|(Int(4))).#(#(String(_).R?C|kotlin/to|(Int(5)))) } public final fun id(arg: R|T|): R|T| { ^id R|/arg| diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java index 24c2c868f09..2a22bb85a40 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java @@ -84,6 +84,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes runTest("compiler/fir/resolve/testData/resolve/stdlib/mapList.kt"); } + @TestMetadata("recursiveBug.kt") + public void testRecursiveBug() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.kt"); + } + @TestMetadata("reflectionClass.kt") public void testReflectionClass() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt"); diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirNamedReference.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirNamedReference.kt index 10b0018c862..6401ae6a5c4 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirNamedReference.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirNamedReference.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir +import org.jetbrains.kotlin.fir.symbols.ConeSymbol import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.name.Name @@ -12,6 +13,8 @@ import org.jetbrains.kotlin.name.Name interface FirNamedReference : FirReference { val name: Name + val candidateSymbol: ConeSymbol? get() = null + override fun accept(visitor: FirVisitor, data: D): R = visitor.visitNamedReference(this, data) } \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index eafd05ebe6b..70ae38f8c72 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -783,10 +783,18 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() { } override fun visitNamedReference(namedReference: FirNamedReference) { - if (namedReference is FirErrorNamedReference) { - print("<${namedReference.errorReason}>#") - } else { - print("${namedReference.name}#") + val symbol = namedReference.candidateSymbol + when { + symbol != null -> { + print("R?C|") + if (symbol is ConeCallableSymbol) + print(symbol.callableId) + else if (symbol is ConeClassLikeSymbol) + print(symbol.classId) + print("|") + } + namedReference is FirErrorNamedReference -> print("<${namedReference.errorReason}>#") + else -> print("${namedReference.name}#") } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirResolvedCallableReferenceImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirResolvedCallableReferenceImpl.kt index b93a8d6d912..b6f8eb587d6 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirResolvedCallableReferenceImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirResolvedCallableReferenceImpl.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.symbols.ConeSymbol import org.jetbrains.kotlin.name.Name -open class FirResolvedCallableReferenceImpl( +class FirResolvedCallableReferenceImpl( session: FirSession, psi: PsiElement?, override val name: Name, diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirSimpleNamedReference.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirSimpleNamedReference.kt index 4a0d02b8d33..6f349afbf61 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirSimpleNamedReference.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/references/FirSimpleNamedReference.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.fir.FirNamedReference import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.name.Name -class FirSimpleNamedReference( +open class FirSimpleNamedReference( session: FirSession, psi: PsiElement?, override val name: Name diff --git a/compiler/testData/ir/irText/expressions/genericPropertyCall.fir.txt b/compiler/testData/ir/irText/expressions/genericPropertyCall.fir.txt index 4b487641fb9..ee8d40402a6 100644 --- a/compiler/testData/ir/irText/expressions/genericPropertyCall.fir.txt +++ b/compiler/testData/ir/irText/expressions/genericPropertyCall.fir.txt @@ -8,7 +8,7 @@ FILE fqName: fileName:/genericPropertyCall.kt PROPERTY name:test visibility:public modality:FINAL [val] FIELD PROPERTY_BACKING_FIELD name:test type:IrErrorType visibility:public [final,static] EXPRESSION_BODY - CALL 'public final fun (): IrErrorType declared in ' type=IrErrorType origin=null + ERROR_CALL 'Unresolved reference: R?C|/id|' type=IrErrorType FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:IrErrorType correspondingProperty: PROPERTY name:test visibility:public modality:FINAL [val] BLOCK_BODY diff --git a/compiler/testData/ir/irText/expressions/variableAsFunctionCallWithGenerics.fir.txt b/compiler/testData/ir/irText/expressions/variableAsFunctionCallWithGenerics.fir.txt index c996eddf520..cb5219b8bdf 100644 --- a/compiler/testData/ir/irText/expressions/variableAsFunctionCallWithGenerics.fir.txt +++ b/compiler/testData/ir/irText/expressions/variableAsFunctionCallWithGenerics.fir.txt @@ -14,7 +14,7 @@ FILE fqName: fileName:/variableAsFunctionCallWithGenerics.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun testGeneric1 (x: kotlin.String): T of declared in ' CALL 'public abstract fun invoke (): T of declared in kotlin.Function0' type=T of origin=null - $this: CALL 'public final fun (): kotlin.Function0> declared in ' type=kotlin.Function0> origin=null + $this: ERROR_CALL 'Unresolved reference: R?C|/gk|' type=kotlin.Function0> PROPERTY name:kt26531Val visibility:public modality:FINAL [val] FUN name: visibility:public modality:FINAL <> () returnType:kotlin.Function0> correspondingProperty: PROPERTY name:kt26531Val visibility:public modality:FINAL [val] @@ -30,4 +30,4 @@ FILE fqName: fileName:/variableAsFunctionCallWithGenerics.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun kt26531 (): T of declared in ' CALL 'public abstract fun invoke (): T of declared in kotlin.Function0' type=T of origin=null - $this: CALL 'public final fun (): kotlin.Function0> declared in ' type=kotlin.Function0> origin=null + $this: ERROR_CALL 'Unresolved reference: R?C|/kt26531Val|' type=kotlin.Function0>