diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt index 51eac6a7ef4..bff94a0be79 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt @@ -252,7 +252,6 @@ fun extractLambdaInfoFromFunctionalType( } if (!expectedType.isBuiltinFunctionalType(session)) return null - val receiverType = argument.receiverType ?: expectedType.receiverType(session) val lastStatement = argument.body?.statements?.singleOrNull() val returnType = // Simply { }, i.e., function literals without body. Raw FIR added an implicit return with an implicit unit type ref. @@ -262,14 +261,16 @@ fun extractLambdaInfoFromFunctionalType( session.builtinTypes.unitType.type else argument.returnType ?: expectedType.returnType(session) + // `fun (x: T) = ...` and `fun T.() = ...` are both instances of `T.() -> V`; `fun () = ...` is not. + // For lambdas, the existence of the receiver is always implied by the expected type, and a value parameter + // can never fill its role. + val receiverType = if (argument.isLambda) expectedType.receiverType(session) else argument.receiverType val expectedParameters = expectedType.valueParameterTypesIncludingReceiver(session).let { - if (expectedType.isExtensionFunctionType(session)) it.drop(1) else it + if (receiverType != null && expectedType.isExtensionFunctionType(session)) it.drop(1) else it } - val parameters = if (argument.valueParameters.isEmpty()) { - expectedParameters + val parameters = if (argument.isLambda && argument.valueParameters.isEmpty() && expectedParameters.size < 2) { + expectedParameters // Infer existence of a parameter named `it` of an appropriate type. } else { - // TODO: `(A) -> B` is permitted as `A.() -> B` if it's an anonymous function, not a lambda; - // e.g. `fun (x: Any?) = x` can be used as `Any?.() -> Any?`, but `{ it -> it }` cannot. argument.valueParameters.mapIndexed { index, parameter -> parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: session.builtinTypes.nothingType.type } diff --git a/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt b/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt index 4dd88964faa..b171ef0b6ea 100644 --- a/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt +++ b/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt @@ -3,8 +3,8 @@ fun text() { "direct:a" to "mock:a" "direct:a" on {it.body == ""} to "mock:a" "direct:a" on {it -> it.body == ""} to "mock:a" - bar {1} - bar {it + 1} + bar {1} + bar {it + 1} bar {it, it1 -> it} bar1 {1} diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.fir.kt b/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.fir.kt index a4249156f1e..ed8693f6b60 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.fir.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.fir.kt @@ -1,3 +1,3 @@ // !WITH_NEW_INFERENCE fun foo(f: String.() -> Int) {} -val test = foo(fun () = length) +val test = foo(fun () = length) diff --git a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt index f026618df0f..c9ef4f81daf 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt @@ -31,7 +31,7 @@ fun test1() { foo2 { - "" + "" } foo2 { s: String -> "" @@ -40,6 +40,6 @@ fun test1() { x -> "" } foo2 { - -> 42 + -> 42 } } diff --git a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt index dc35cde2de0..6eb49eb6ef7 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt @@ -20,5 +20,5 @@ fun testFunctions() { fun testNestedCalls() { id(inferFromLambda { materialize() }) id(inferFromLambda(fun() = materialize())) - id(inferFromLambda2(fun() = materialize())) + id(inferFromLambda2(fun() = materialize())) } diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt index 480bdc24d4b..87bdcc67010 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -228,7 +228,7 @@ fun main() { val x70: (Int) -> Unit = selectNumber(id(fun (it) { }), id {}, id {}) val x71: String.() -> Unit = select(")!>id(fun String.() { }), ")!>id(fun(x: String) {})) val x72: String.() -> Unit = select(fun String.() { }, fun(x: String) {}) // must be error - select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { x;y }) + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { x;y }) select(id Unit>(fun (x, y) {}), { x: Int, y: String -> x }) // receiver of anonymous function must be specified explicitly select(id Unit>(fun Int.(y) {}), { x: Int, y: String -> x }) ")!>select(A3(), fun (x) = "", { a -> a }) diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt index 7af615291cb..8b844f809cd 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt @@ -111,7 +111,7 @@ fun test3() { // to non-extension lambda 1 // val i32: L1 = id { this } // this or it: oi- ni- // val j32 = id { this } // this or it: oi- ni- - val w33 = W3(fun Int.(): Int = this) // oi- ni+ + val w33 = W3(fun Int.(): Int = this) // oi- ni+ val i33: L1 = id(fun Int.(): Int = this) // oi+ ni+ // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)