diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 21e84582487..3bd00ca1dcb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -18,14 +18,12 @@ import org.jetbrains.kotlin.fir.references.impl.FirResolvedCallableReferenceImpl import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirExpressionsResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir -import org.jetbrains.kotlin.fir.resolve.typeForQualifier -import org.jetbrains.kotlin.fir.resolve.typeFromCallee -import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol @@ -226,7 +224,8 @@ class FirCallResolver( ): Boolean { val callableReferenceAccess = resolvedCallableReferenceAtom.atom val lhs = resolvedCallableReferenceAtom.lhs - val expectedType = resolvedCallableReferenceAtom.expectedType ?: return false + val coneSubstitutor = constraintSystemBuilder.buildCurrentSubstitutor() as ConeSubstitutor + val expectedType = resolvedCallableReferenceAtom.expectedType?.let(coneSubstitutor::substituteOrSelf) ?: return false val result = CandidateCollector(this, resolutionStageRunner) val consumer = @@ -250,7 +249,8 @@ class FirCallResolver( return false } reducedCandidates.size > 1 -> { - // TODO: add postponed atom + if (resolvedCallableReferenceAtom.postponed) return false + resolvedCallableReferenceAtom.postponed = true return true } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArguments.kt index de5b507ce37..3b3dd819444 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArguments.kt @@ -11,8 +11,10 @@ import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS import org.jetbrains.kotlin.fir.resolve.constructType import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.invoke import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -211,6 +213,7 @@ abstract class ResolvedCallableReferenceAtom( val lhs: DoubleColonLHS? ) : PostponedResolvedAtomMarker { override var analyzed: Boolean = false + var postponed: Boolean = false var resultingCandidate: Pair? = null } @@ -221,6 +224,63 @@ class EagerCallableReferenceAtom( lhs: DoubleColonLHS? ) : ResolvedCallableReferenceAtom(atom, expectedType, lhs) { - override val inputTypes: Collection get() = emptyList() - override val outputType: ConeKotlinType? get() = null + override val inputTypes: Collection + get() { + if (!postponed) return emptyList() + return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.inputTypes ?: listOfNotNull(expectedType) + } + override val outputType: ConeKotlinType? + get() { + if (!postponed) return null + return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.outputType + } +} + +private data class InputOutputTypes(val inputTypes: List, val outputType: ConeKotlinType) + +private fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: ConeKotlinType?): InputOutputTypes? { + if (expectedType == null) return null + + return when { + expectedType.isBuiltinFunctionalType || expectedType.isSuspendFunctionType -> + extractInputOutputTypesFromFunctionType(expectedType) + +// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) -> +// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap()) +// +// ReflectionTypes.isNumberedKFunction(expectedType) -> { +// val functionFromSupertype = expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap() +// extractInputOutputTypesFromFunctionType(functionFromSupertype) +// } +// +// ReflectionTypes.isNumberedKSuspendFunction(expectedType) -> { +// val kSuspendFunctionType = expectedType.immediateSupertypes().first { it.isSuspendFunctionType }.unwrap() +// extractInputOutputTypesFromFunctionType(kSuspendFunctionType) +// } +// +// ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(expectedType) -> { +// val functionFromSupertype = expectedType.supertypes().first { it.isFunctionType }.unwrap() +// extractInputOutputTypesFromFunctionType(functionFromSupertype) +// } + + else -> null + } +} + +private fun extractInputOutputTypesFromFunctionType(functionType: ConeKotlinType): InputOutputTypes { + val receiver = null// TODO: functionType.receiverType() + val parameters = functionType.valueParameterTypes.map { + it ?: ConeClassTypeImpl( + ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(), + isNullable = false + ) + } + + val inputTypes = /*listOfNotNull(receiver) +*/ parameters + val outputType = functionType.returnType ?: ConeClassTypeImpl( + ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(), + isNullable = true + ) + + return InputOutputTypes(inputTypes, outputType) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt index 885fc098399..20aab62ad5d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.calls +import org.jetbrains.kotlin.fir.FirCallResolver import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl @@ -43,7 +44,8 @@ class PostponedArgumentsAnalyzer( private val typeProvider: (FirExpression) -> FirTypeRef?, private val components: InferenceComponents, private val candidate: Candidate, - private val replacements: MutableMap + private val replacements: MutableMap, + private val callResolver: FirCallResolver ) { fun analyze( @@ -70,6 +72,10 @@ class PostponedArgumentsAnalyzer( } private fun processCallableReference(atom: ResolvedCallableReferenceAtom) { + if (atom.postponed) { + callResolver.resolveCallableReference(candidate.csBuilder, atom) + } + val callableReferenceAccess = atom.atom atom.analyzed = true val (candidate, applicability) = atom.resultingCandidate ?: Pair(null, CandidateApplicability.INAPPLICABLE) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt index 1589c802231..70d9fe4896a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt @@ -71,7 +71,9 @@ class FirCallCompleter( val replacements = mutableMapOf() val analyzer = - PostponedArgumentsAnalyzer(LambdaAnalyzerImpl(replacements), { it.resultType }, inferenceComponents, candidate, replacements) + PostponedArgumentsAnalyzer( + LambdaAnalyzerImpl(replacements), { it.resultType }, inferenceComponents, candidate, replacements, transformer.callResolver + ) completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) { analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it) diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/applicableCallableReferenceFromDistantScope.txt b/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/applicableCallableReferenceFromDistantScope.txt index a8ac23e6a06..7ecaa8d8c9b 100644 --- a/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/applicableCallableReferenceFromDistantScope.txt +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/applicableCallableReferenceFromDistantScope.txt @@ -17,7 +17,7 @@ FILE: applicableCallableReferenceFromDistantScope.kt } public final fun test(): R|kotlin/Unit| { - lval s: R|kotlin/String| = this@R|/Scope|.R|/Scope.bar|(::#) + lval s: R|kotlin/String| = this@R|/Scope|.R|/Scope.bar|(::R|/foo|) } } diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/eagerAndPostponedCallableReferences.txt b/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/eagerAndPostponedCallableReferences.txt index 720447581bd..f6bd5dbda9c 100644 --- a/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/eagerAndPostponedCallableReferences.txt +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/eagerAndPostponedCallableReferences.txt @@ -15,10 +15,10 @@ FILE: eagerAndPostponedCallableReferences.kt ^foo R|kotlin/TODO|() } public final fun test(): R|kotlin/Unit| { - lval a1: R|A| = R|/foo|(::R|/singleA|, ::#) - lval a2: R|B| = R|/foo|(::R|/singleB|, ::#) - lval a3: R|A| = R|/foo|(::#, ::R|/singleA|) - lval a4: R|B| = R|/foo|(::#, ::R|/singleB|) + lval a1: R|A| = R|/foo|(::R|/singleA|, ::R|/multiple|) + lval a2: R|B| = R|/foo|(::R|/singleB|, ::R|/multiple|) + lval a3: R|A| = R|/foo|(::R|/multiple|, ::R|/singleA|) + lval a4: R|B| = R|/foo|(::R|/multiple|, ::R|/singleB|) lval a5: R|A| = R|/foo|(::R|/singleA|, ::R|/singleA|) lval a6: R|it(A & B)| = R|/foo|(::R|/singleA|, ::R|/singleB|) R|/foo|(::#, ::#) diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/postponedResolveOfManyCallableReference.txt b/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/postponedResolveOfManyCallableReference.txt index 6990668401e..bc88ceaa0cc 100644 --- a/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/postponedResolveOfManyCallableReference.txt +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/fromBasicDiagnosticTests/postponedResolveOfManyCallableReference.txt @@ -13,8 +13,8 @@ FILE: postponedResolveOfManyCallableReference.kt public final fun bar2(f: R|kotlin/Function1|, e: R|T|): R|kotlin/Unit| { } public final fun test(a: R|A|, b: R|B|): R|kotlin/Unit| { - lval expectedType1: R|A| = R|/bar1|(::#) - lval expectedType2: R|B| = R|/bar1|(::#) + lval expectedType1: R|A| = R|/bar1|(::R|/foo|) + lval expectedType2: R|B| = R|/bar1|(::R|/foo|) R|/bar2|(::R|/foo|, R|/a|) R|/bar2|(::R|/foo|, R|/b|) }