diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index c3b1fdaeeee..c7f9b7ae916 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt @@ -97,7 +97,15 @@ private fun extraLambdaInfo( val newTypeVariableUsed = returnType == typeVariable.defaultType if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable) - return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed }) + return ResolvedLambdaAtom( + argument, + isSuspend, + receiverType, + parameters, + returnType, + typeVariable.takeIf { newTypeVariableUsed }, + expectedType + ) } private fun extractLambdaInfoFromFunctionalType(expectedType: UnwrappedType?, argument: LambdaKotlinCallArgument): ResolvedLambdaAtom? { @@ -114,7 +122,8 @@ private fun extractLambdaInfoFromFunctionalType(expectedType: UnwrappedType?, ar receiverType, parameters, returnType, - typeVariableForLambdaReturnType = null + typeVariableForLambdaReturnType = null, + expectedType = expectedType ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 31c05c564c3..630e3631758 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -5,6 +5,9 @@ package org.jetbrains.kotlin.resolve.calls.components +import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType +import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType +import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemFromArgument import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor @@ -68,15 +71,31 @@ class PostponedArgumentsAnalyzer( fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type) - val receiver = lambda.receiver?.let(::substitute) - val parameters = lambda.parameters.map(::substitute) + fun expectedOrActualType(expected: UnwrappedType?, actual: UnwrappedType?): UnwrappedType? { + val expectedSubstituted = expected?.let(::substitute) + return if (expectedSubstituted != null && c.canBeProper(expectedSubstituted)) expectedSubstituted else actual?.let(::substitute) + } + + val builtIns = c.getBuilder().builtIns + + // Expected type has a higher priority against which lambda should be analyzed + // Mostly, this is needed to report more specific diagnostics on lambda parameters + val receiver = expectedOrActualType(lambda.expectedType.receiver(), lambda.receiver) + + val expectedParameters = lambda.expectedType.valueParameters() + + val parameters = + expectedParameters?.mapIndexed { index, expected -> + expectedOrActualType(expected, lambda.parameters.getOrNull(index)) ?: builtIns.nothingType + } ?: lambda.parameters.map(::substitute) + val rawReturnType = lambda.returnType val expectedTypeForReturnArguments = when { c.canBeProper(rawReturnType) -> substitute(rawReturnType) // For Unit-coercion - c.hasUpperOrEqualUnitConstraint(rawReturnType) -> lambda.returnType.builtIns.unitType + c.hasUpperOrEqualUnitConstraint(rawReturnType) -> builtIns.unitType else -> null } @@ -121,4 +140,16 @@ class PostponedArgumentsAnalyzer( } } } + + private fun UnwrappedType?.receiver(): UnwrappedType? { + return forFunctionalType { getReceiverTypeFromFunctionType()?.unwrap() } + } + + private fun UnwrappedType?.valueParameters(): List? { + return forFunctionalType { getValueParameterTypesFromFunctionType().map { it.type.unwrap() } } + } + + private inline fun UnwrappedType?.forFunctionalType(f: UnwrappedType.() -> T?): T? { + return if (this?.isBuiltinFunctionalType == true) f(this) else null + } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index 43860b3b842..6e1347f543c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -94,7 +94,8 @@ class ResolvedLambdaAtom( val receiver: UnwrappedType?, val parameters: List, val returnType: UnwrappedType, - val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType? + val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?, + val expectedType: UnwrappedType? ) : PostponedResolvedAtom() { lateinit var resultArguments: List private set diff --git a/compiler/testData/diagnostics/tests/AutoCreatedIt.kt b/compiler/testData/diagnostics/tests/AutoCreatedIt.kt index db0b1006919..e012e7a9eee 100644 --- a/compiler/testData/diagnostics/tests/AutoCreatedIt.kt +++ b/compiler/testData/diagnostics/tests/AutoCreatedIt.kt @@ -13,7 +13,7 @@ fun text() { bar2 {} bar2 {1} bar2 {it} - bar2 {it -> it} + bar2 {it -> it} } fun bar(f : (Int, Int) -> Int) {} diff --git a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt index 64614f9b010..9bb5e8c019c 100644 --- a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt +++ b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt @@ -37,8 +37,8 @@ fun main(args : Array) { foo2()({}) foo2(){} (foo2()){} - (foo2()){x -> } - foo2()({x -> }) + (foo2()){x -> } + foo2()({x -> }) val a = fooT1(1)() checkSubtype(a) diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt b/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt index 34b51623d59..442c7f3c2a2 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt @@ -19,9 +19,9 @@ fun test1(a: (Int) -> Unit) { } fun test2(a: (Int) -> Unit) { - test2(fun (x: String) {}) + test2(fun (x: String) {}) } fun test3(a: (Int, String) -> Unit) { - test3(fun (x: String) {}) + test3(fun (x: String) {}) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt index dc14a07cfac..36d113e6f6f 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt @@ -16,6 +16,6 @@ fun test(s: Sub) { t: Trait -> s } - foo(fun(t: Sub) = s) + foo(fun(t: Sub) = s) foo(fun(t): Super = s) } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt index cb87406a4d8..8e41ca760af 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt @@ -10,23 +10,23 @@ fun test1() { "" } foo0 { - s: String-> "" + s: String-> "" } foo0 { - x, y -> "" + x, y -> "" } foo1 { "" } foo1 { - s: String -> "" + s: String -> "" } foo1 { - x, y -> "" + x, y -> "" } foo1 { - -> 42 + -> 42 } @@ -34,12 +34,12 @@ fun test1() { "" } foo2 { - s: String -> "" + s: String -> "" } foo2 { - x -> "" + x -> "" } foo2 { - -> 42 + -> 42 } } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt index 7f7ca456609..5ef660246c2 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt @@ -47,7 +47,7 @@ fun bar() { b checkType { _() } } - foo { (a, b): B -> + foo { (a, b): B -> a checkType { _() } b checkType { _() } } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt index 5bae03b2eff..a81c28ab87f 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt @@ -56,7 +56,7 @@ fun bar() { b checkType { _() } } - foo { (_, b): B -> + foo { (_, b): B -> _.hashCode() b checkType { _() } } diff --git a/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.kt b/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.kt index afcc28e4168..9f59e7247b8 100644 --- a/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.kt +++ b/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.kt @@ -16,12 +16,12 @@ public interface J2 extends J { // FILE: main.kt fun main() { - J { s: String -> s} // should be prohibited, because SAM value parameter has nullable type + J { s: String -> s} // should be prohibited, because SAM value parameter has nullable type J { "" + it.length } J { null } J { it?.length?.toString() } - J2 { s: String -> s} + J2 { s: String -> s} J2 { "" + it.length } J2 { null } J2 { it?.length?.toString() } diff --git a/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt b/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt index b238e4b8658..4011f9bdcc4 100644 --- a/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt +++ b/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt @@ -19,7 +19,7 @@ val test3: (String) -> Boolean = val test4: (String) -> Boolean = when { - true -> { s1, s2 -> true } + true -> { s1, s2 -> true } else -> null!! }