diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index a0eac050faf..5edf6c675a4 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -2743,6 +2743,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/callableReference/resolve/multipleOutersAndMultipleCallableReferences.kt"); } + @TestMetadata("nestedReferenceCallAgainstExpectedType.kt") + public void testNestedReferenceCallAgainstExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.kt"); + } + @TestMetadata("noAmbiguityBetweenTopLevelAndMemberProperty.kt") public void testNoAmbiguityBetweenTopLevelAndMemberProperty() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/resolve/noAmbiguityBetweenTopLevelAndMemberProperty.kt"); @@ -2753,6 +2758,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/callableReference/resolve/noFakeDescriptorForObject.kt"); } + @TestMetadata("overloadAmbiguityForSimpleLastExpressionOfBlock.kt") + public void testOverloadAmbiguityForSimpleLastExpressionOfBlock() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.kt"); + } + @TestMetadata("overloads.kt") public void testOverloads() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/resolve/overloads.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index b54d41b8ddb..5cf1bd3ea81 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -14,12 +14,12 @@ import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.referenceExpression import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.BindingContext.NEW_INFERENCE_CATCH_EXCEPTION_PARAMETER import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver +import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator import org.jetbrains.kotlin.resolve.calls.callUtil.* import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver @@ -92,7 +92,7 @@ class PSICallResolver( val refinedName = refineNameForRemOperator(isBinaryRemOperator, name) val kotlinCallKind = resolutionKind.toKotlinCallKind() - val kotlinCall = toKotlinCall(context, kotlinCallKind, context.call, refinedName, tracingStrategy) + val kotlinCall = toKotlinCall(context, kotlinCallKind, context.call, refinedName, tracingStrategy, isSpecialFunction = false) val scopeTower = ASTScopeTower(context) val resolutionCallbacks = createResolutionCallbacks(context) @@ -125,8 +125,10 @@ class PSICallResolver( ): OverloadResolutionResults { val dispatchReceiver = resolutionCandidates.firstNotNullResult { it.dispatchReceiver } - val kotlinCall = - toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, givenCandidatesName, tracingStrategy, dispatchReceiver) + val isSpecialFunction = resolutionCandidates.any { it.descriptor.name in SPECIAL_FUNCTION_NAMES } + val kotlinCall = toKotlinCall( + context, KotlinCallKind.FUNCTION, context.call, givenCandidatesName, tracingStrategy, isSpecialFunction, dispatchReceiver + ) val scopeTower = ASTScopeTower(context) val resolutionCallbacks = createResolutionCallbacks(context) @@ -163,7 +165,9 @@ class PSICallResolver( expectedType: UnwrappedType? ): CallResolutionResult { val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! - val callWithDeprecatedName = toKotlinCall(context, kotlinCallKind, context.call, deprecatedName, tracingStrategy) + val callWithDeprecatedName = toKotlinCall( + context, kotlinCallKind, context.call, deprecatedName, tracingStrategy, isSpecialFunction = false + ) return kotlinCallResolver.resolveCall( scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, context.collectAllCandidates ) { @@ -558,7 +562,8 @@ class PSICallResolver( oldCall: Call, name: Name, tracingStrategy: TracingStrategy, - forcedExplicitReceiver: Receiver? = null + isSpecialFunction: Boolean, + forcedExplicitReceiver: Receiver? = null, ): PSIKotlinCallImpl { val resolvedExplicitReceiver = resolveReceiver( context, forcedExplicitReceiver ?: oldCall.explicitReceiver, oldCall.isSafeCall(), isForImplicitInvoke = false @@ -574,7 +579,7 @@ class PSICallResolver( val argumentsInParenthesis = if (extraArgumentsNumber == 0) allValueArguments else allValueArguments.dropLast(extraArgumentsNumber) val externalLambdaArguments = oldCall.functionLiteralArguments - val resolvedArgumentsInParenthesis = resolveArgumentsInParenthesis(context, argumentsInParenthesis) + val resolvedArgumentsInParenthesis = resolveArgumentsInParenthesis(context, argumentsInParenthesis, isSpecialFunction) val externalArgument = if (oldCall.callType == Call.CallType.ARRAY_SET_METHOD) { assert(externalLambdaArguments.isEmpty()) { @@ -608,7 +613,8 @@ class PSICallResolver( else context.dataFlowInfoForArguments.resultInfo - val resolvedExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) } + val resolvedExternalArgument = + externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it, isSpecialFunction) } val resultDataFlowInfo = resolvedExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) } @@ -690,11 +696,17 @@ class PSICallResolver( private fun resolveArgumentsInParenthesis( context: BasicCallResolutionContext, - arguments: List + arguments: List, + isSpecialFunction: Boolean ): List { val dataFlowInfoForArguments = context.dataFlowInfoForArguments return arguments.map { argument -> - resolveValueArgument(context, dataFlowInfoForArguments.getInfo(argument), argument).also { resolvedArgument -> + resolveValueArgument( + context, + dataFlowInfoForArguments.getInfo(argument), + argument, + isSpecialFunction + ).also { resolvedArgument -> dataFlowInfoForArguments.updateInfo(argument, resolvedArgument.dataFlowInfoAfterThisArgument) } } @@ -703,7 +715,8 @@ class PSICallResolver( private fun resolveValueArgument( outerCallContext: BasicCallResolutionContext, startDataFlowInfo: DataFlowInfo, - valueArgument: ValueArgument + valueArgument: ValueArgument, + isSpecialFunction: Boolean ): PSIKotlinCallArgument { val builtIns = outerCallContext.scope.ownerDescriptor.builtIns @@ -728,8 +741,17 @@ class PSICallResolver( } val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT) - .replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo) - .expandContextForCatchClause(ktExpression) + .replaceDataFlowInfo(startDataFlowInfo) + .expandContextForCatchClause(ktExpression).let { + if (isSpecialFunction && + argumentExpression is KtBlockExpression && + ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, it) != null + ) { + it + } else { + it.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) + } + } if (ktExpression is KtCallableReferenceExpression) { return createCallableReferenceKotlinCallArgument( diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.kt b/compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.kt new file mode 100644 index 00000000000..adfb7090898 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.kt @@ -0,0 +1,25 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface A +interface B + +fun foo(a: A) {} +fun foo(b: B) {} + +fun bar(a: A) {} + +val l0: (A) -> Unit + get() = + if (1 < 2) { + ::foo + } else { + ::bar + } + +val l1: (A) -> Unit + get() = when { + true -> ::foo + false -> { ::foo } + else -> ::bar + } diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.txt b/compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.txt new file mode 100644 index 00000000000..92a80a8ae4b --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.txt @@ -0,0 +1,19 @@ +package + +public val l0: (A) -> kotlin.Unit +public val l1: (A) -> kotlin.Unit +public fun bar(/*0*/ a: A): kotlin.Unit +public fun foo(/*0*/ a: A): kotlin.Unit +public fun foo(/*0*/ b: B): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.fir.kt b/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.fir.kt new file mode 100644 index 00000000000..a1e617ea8a3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.fir.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface A +interface B +object C : A, B + +fun foo(a: A): Int = 0 +fun foo(b: B): Double = 0.0 + +fun bar(a: A): Int = 0 + +val l0: Int + get() = + if (1 < 2) { + foo(C) + } else { + bar(C) + } + +val l1: Int + get() = when { + true -> foo(C) + false -> { foo(C) } + else -> bar(C) + } diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.kt b/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.kt new file mode 100644 index 00000000000..017e5efbbec --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface A +interface B +object C : A, B + +fun foo(a: A): Int = 0 +fun foo(b: B): Double = 0.0 + +fun bar(a: A): Int = 0 + +val l0: Int + get() = + if (1 < 2) { + foo(C) + } else { + bar(C) + } + +val l1: Int + get() = when { + true -> foo(C) + false -> { foo(C) } + else -> bar(C) + } diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.txt b/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.txt new file mode 100644 index 00000000000..6357f92c666 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.txt @@ -0,0 +1,26 @@ +package + +public val l0: kotlin.Int +public val l1: kotlin.Int +public fun bar(/*0*/ a: A): kotlin.Int +public fun foo(/*0*/ a: A): kotlin.Int +public fun foo(/*0*/ b: B): kotlin.Double + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object C : A, B { + private constructor C() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 388d9a6faa3..53d49da59d6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2750,6 +2750,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/callableReference/resolve/multipleOutersAndMultipleCallableReferences.kt"); } + @TestMetadata("nestedReferenceCallAgainstExpectedType.kt") + public void testNestedReferenceCallAgainstExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.kt"); + } + @TestMetadata("noAmbiguityBetweenTopLevelAndMemberProperty.kt") public void testNoAmbiguityBetweenTopLevelAndMemberProperty() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/resolve/noAmbiguityBetweenTopLevelAndMemberProperty.kt"); @@ -2760,6 +2765,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/callableReference/resolve/noFakeDescriptorForObject.kt"); } + @TestMetadata("overloadAmbiguityForSimpleLastExpressionOfBlock.kt") + public void testOverloadAmbiguityForSimpleLastExpressionOfBlock() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.kt"); + } + @TestMetadata("overloads.kt") public void testOverloads() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/resolve/overloads.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 8df9d580b7b..e6966540eab 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -2745,6 +2745,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/callableReference/resolve/multipleOutersAndMultipleCallableReferences.kt"); } + @TestMetadata("nestedReferenceCallAgainstExpectedType.kt") + public void testNestedReferenceCallAgainstExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/resolve/nestedReferenceCallAgainstExpectedType.kt"); + } + @TestMetadata("noAmbiguityBetweenTopLevelAndMemberProperty.kt") public void testNoAmbiguityBetweenTopLevelAndMemberProperty() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/resolve/noAmbiguityBetweenTopLevelAndMemberProperty.kt"); @@ -2755,6 +2760,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/callableReference/resolve/noFakeDescriptorForObject.kt"); } + @TestMetadata("overloadAmbiguityForSimpleLastExpressionOfBlock.kt") + public void testOverloadAmbiguityForSimpleLastExpressionOfBlock() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/resolve/overloadAmbiguityForSimpleLastExpressionOfBlock.kt"); + } + @TestMetadata("overloads.kt") public void testOverloads() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/resolve/overloads.kt");