diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java index 083bdfc2daf..2e1fd4f146f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java @@ -56,6 +56,7 @@ import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumen import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS; import static org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke; import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT; +import static org.jetbrains.kotlin.resolve.calls.inference.InferencePackage.createCorrespondingExtensionFunctionTypeIfNecessary; import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION; import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION; import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*; @@ -536,13 +537,13 @@ public class CandidateResolver { } else if (!noExpectedType(expectedType)) { if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) { - JetType smartCastType = smartCastValueArgumentTypeIfPossible(expression, expectedType, type, newContext); - if (smartCastType == null) { + JetType morePreciseType = makeMorePreciseType(type, expression, newContext); + if (morePreciseType == null) { resultStatus = OTHER_ERROR; matchStatus = ArgumentMatchStatus.TYPE_MISMATCH; } else { - resultingType = smartCastType; + resultingType = morePreciseType; } } else if (ErrorUtils.containsUninferredParameter(expectedType)) { @@ -556,6 +557,27 @@ public class CandidateResolver { return new ValueArgumentsCheckingResult(resultStatus, argumentTypes); } + @Nullable + private static > JetType makeMorePreciseType( + @NotNull JetType type, + @NotNull JetExpression expression, + @NotNull CallResolutionContext context + ) { + JetType smartCastType = smartCastValueArgumentTypeIfPossible(expression, context.expectedType, type, context); + if (smartCastType != null) { + return smartCastType; + } + // function literal without declaring receiver type { x -> ... } + // can be considered as extension function if one is expected + if (ArgumentTypeResolver.isFunctionLiteralArgument(expression, context)) { + JetType extensionFunctionType = createCorrespondingExtensionFunctionTypeIfNecessary(type, context.expectedType); + if (ArgumentTypeResolver.isSubtypeOfForArgumentType(extensionFunctionType, context.expectedType)) { + return extensionFunctionType; + } + } + return null; + } + @Nullable private static JetType smartCastValueArgumentTypeIfPossible( @NotNull JetExpression expression, diff --git a/compiler/testData/diagnostics/tests/overload/kt7068.kt b/compiler/testData/diagnostics/tests/overload/kt7068.kt new file mode 100644 index 00000000000..7a988fe4bf7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/overload/kt7068.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun withLambda(block : Int.(String) -> Unit) { +} + +fun withLambda(o : Int, block : Int.(String) -> Unit) { +} + +fun test() { + withLambda { + it.length() + } + + withLambda { r -> // no error should be here + r.length() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/overload/kt7068.txt b/compiler/testData/diagnostics/tests/overload/kt7068.txt new file mode 100644 index 00000000000..681bef27a37 --- /dev/null +++ b/compiler/testData/diagnostics/tests/overload/kt7068.txt @@ -0,0 +1,5 @@ +package + +internal fun test(): kotlin.Unit +internal fun withLambda(/*0*/ o: kotlin.Int, /*1*/ block: kotlin.Int.(kotlin.String) -> kotlin.Unit): kotlin.Unit +internal fun withLambda(/*0*/ block: kotlin.Int.(kotlin.String) -> kotlin.Unit): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/overload/kt7068_2.kt b/compiler/testData/diagnostics/tests/overload/kt7068_2.kt new file mode 100644 index 00000000000..fe95127b85d --- /dev/null +++ b/compiler/testData/diagnostics/tests/overload/kt7068_2.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun withLambda(block : Int.(String) -> Unit) { +} + +fun withLambda(block : Int.(String, String) -> Unit) { +} + +fun test() { + withLambda { r -> + r.length() + } + + withLambda { x, y -> + x.length() + y.length() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/overload/kt7068_2.txt b/compiler/testData/diagnostics/tests/overload/kt7068_2.txt new file mode 100644 index 00000000000..f9afeed7a8e --- /dev/null +++ b/compiler/testData/diagnostics/tests/overload/kt7068_2.txt @@ -0,0 +1,5 @@ +package + +internal fun test(): kotlin.Unit +internal fun withLambda(/*0*/ block: kotlin.Int.(kotlin.String) -> kotlin.Unit): kotlin.Unit +internal fun withLambda(/*0*/ block: kotlin.Int.(kotlin.String, kotlin.String) -> kotlin.Unit): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 74273ef51c2..8c367bd4660 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -8443,6 +8443,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt7068.kt") + public void testKt7068() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/kt7068.kt"); + doTest(fileName); + } + + @TestMetadata("kt7068_2.kt") + public void testKt7068_2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/kt7068_2.kt"); + doTest(fileName); + } + @TestMetadata("OverloadFunRegularAndExt.kt") public void testOverloadFunRegularAndExt() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/OverloadFunRegularAndExt.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index a879972d631..cee2e1d7b9a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -270,10 +270,8 @@ public class ConstraintSystemImpl : ConstraintSystem { // function literal without declaring receiver type { x -> ... } // can be considered as extension function if one is expected // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE) - val newSubType = if (constraintKind == SUB_TYPE - && KotlinBuiltIns.isFunctionType(subType) - && KotlinBuiltIns.isExtensionFunctionType(superType)) { - createCorrespondingExtensionFunctionType(subType, DONT_CARE) + val newSubType = if (constraintKind == SUB_TYPE) { + createCorrespondingExtensionFunctionTypeIfNecessary(subType, superType) } else { subType : JetType @@ -422,26 +420,33 @@ public class ConstraintSystemImpl : ConstraintSystem { override fun getResultingSubstitutor() = replaceUninferredBySpecialErrorType().setApproximateCapturedTypes() override fun getCurrentSubstitutor() = replaceUninferredBy(TypeUtils.DONT_CARE).setApproximateCapturedTypes() +} - private fun createCorrespondingExtensionFunctionType(functionType: JetType, receiverType: JetType): JetType { - assert(KotlinBuiltIns.isFunctionType(functionType)) - - val typeArguments = functionType.getArguments() - assert(!typeArguments.isEmpty()) - - val arguments = ArrayList() - // excluding the last type argument of the function type, which is the return type - var index = 0 - val lastIndex = typeArguments.size() - 1 - for (typeArgument in typeArguments) { - if (index < lastIndex) { - arguments.add(typeArgument.getType()) - } - index++ - } - val returnType = typeArguments.get(lastIndex).getType() - return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType) +fun createCorrespondingExtensionFunctionTypeIfNecessary(functionType: JetType, expectedType: JetType): JetType { + if (KotlinBuiltIns.isFunctionType(functionType) && KotlinBuiltIns.isExtensionFunctionType(expectedType)) { + return createCorrespondingExtensionFunctionType(functionType, DONT_CARE) } + return functionType +} + +private fun createCorrespondingExtensionFunctionType(functionType: JetType, receiverType: JetType): JetType { + assert(KotlinBuiltIns.isFunctionType(functionType)) + + val typeArguments = functionType.getArguments() + assert(!typeArguments.isEmpty()) + + val arguments = ArrayList() + // excluding the last type argument of the function type, which is the return type + var index = 0 + val lastIndex = typeArguments.size() - 1 + for (typeArgument in typeArguments) { + if (index < lastIndex) { + arguments.add(typeArgument.getType()) + } + index++ + } + val returnType = typeArguments.get(lastIndex).getType() + return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType) } private fun TypeSubstitutor.setApproximateCapturedTypes(): TypeSubstitutor {