Skip to content

Commit f12cc1f

Browse files
dzharkovSpace Team
authored andcommitted
FE: Support assigning lambdas to receiver/context function types
It's been controversially working since 2.0, but was broken once ResolveTopLevelLambdasAsSyntheticCallArgument became enabled by default. See KT-81115 and related issues for details. ^KT-81115 Fixed
1 parent 280dd18 commit f12cc1f

File tree

7 files changed

+43
-20
lines changed

7 files changed

+43
-20
lines changed

compiler/fir/analysis-tests/testData/resolve/inference/lambdasWithExplicitParametersViaReceiversFeatureEnabled.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
// ISSUE: KT-81115
44

55
val l1: String.() -> String = fun(x: String) = ""
6-
val l2: String.() -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String -> "" }<!>
6+
val l2: String.() -> String = { x: String -> "" }
77

88
val l3: String.() -> String = fun(x) = x
9-
val l4: String.() -> String = <!INITIALIZER_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>x<!> -> x }<!>
9+
val l4: String.() -> String = { x -> x }
1010

1111
val l5: String.(Int) -> String = fun(x: String, y) = ""
12-
val l6: String.(Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>y<!> -> "" }<!>
12+
val l6: String.(Int) -> String = { x: String, y -> "" }
1313

1414
val w1: String.(Int, Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>fun(x: String, y) = ""<!>
1515
val w2: String.(Int, Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, y -> "" }<!>

compiler/fir/analysis-tests/testData/resolve/inference/lambdasWithExplicitParametersWithContexts.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
// ISSUE: KT-81115
44

55
val l1: context(String) (Int) -> String = fun(x: String, y) = ""
6-
val l2: context(String) (Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>y<!> -> "" }<!>
6+
val l2: context(String) (Int) -> String = { x: String, y -> "" }
77

88
val l3: context(String) Double.(Int) -> String = fun(x: String, y, z: Int) = ""
9-
val l4: context(String) Double.(Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>y<!>, z: Int -> "" }<!>
9+
val l4: context(String) Double.(Int) -> String = { x: String, y, z: Int -> "" }
1010

1111
val w1: context(String) Double.(Int, Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>fun(x: String, y, z: Int) = ""<!>
1212
val w2: context(String) Double.(Int, Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, y, z: Int -> "" }<!>

compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,13 @@ class FirSyntheticCallGenerator(
255255
): FirExpression {
256256
val argumentList = buildUnaryArgumentList(anonymousFunctionExpression)
257257

258+
val expectedType =
259+
expectedTypeData?.expectedType?.adaptExpectedTypeForLambdaIfNeeded(anonymousFunctionExpression.anonymousFunction)
260+
258261
val reference = generateCalleeReferenceToFunctionWithExpectedTypeForArgument(
259262
anonymousFunctionExpression,
260263
argumentList,
261-
expectedTypeData?.expectedType,
264+
expectedType,
262265
context,
263266
)
264267

@@ -298,6 +301,26 @@ class FirSyntheticCallGenerator(
298301
return resolvedArgument
299302
}
300303

304+
private fun ConeKotlinType.adaptExpectedTypeForLambdaIfNeeded(lambda: FirAnonymousFunction): ConeKotlinType {
305+
if (!lambda.hasExplicitParameterList) return this
306+
if (!isSomeFunctionType(session)) return this
307+
308+
val isThereReceiver = receiverType(session) != null
309+
if (!isThereReceiver && contextParameterNumberForFunctionType == 0) return this
310+
311+
val classLikeType = unwrapLowerBound() as? ConeClassLikeType ?: return this
312+
313+
return when {
314+
lambda.valueParameters.size == classLikeType.valueParameterTypesIncludingReceiver(session).size ->
315+
classLikeType.withAttributes(
316+
classLikeType.attributes
317+
.remove(CompilerConeAttributes.ExtensionFunctionType::class)
318+
.remove(CompilerConeAttributes.ContextFunctionTypeParams::class)
319+
)
320+
else -> this
321+
}
322+
}
323+
301324
/**
302325
* After resolution of a top-level lambda via synthetic call, we have some diagnostic, which in most of the cases says
303326
* that the type of the lambda can't be passed to the given expected type.

compiler/testData/diagnostics/tests/functionLiterals/kt56138.fir.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ fun takeLambda1(f: String.() -> String) {}
66
fun takeLambda2(f: String.(String) -> String) {}
77

88
fun test_1() {
9-
val x1: String.(String) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ str, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str2<!> -> "this" }<!>
9+
val x1: String.(String) -> String = { str, str2 -> "this" }
1010
val x2: String.() -> String = { <!UNRESOLVED_REFERENCE!>it<!> }
11-
val x3: String.() -> String = <!INITIALIZER_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>x<!> -> "x" }<!>
11+
val x3: String.() -> String = { x -> "x" }
1212
}
1313

1414
fun test_2() {
@@ -19,9 +19,9 @@ fun test_2() {
1919

2020
fun test_3(b: Boolean) {
2121
val x1: String.(String) -> String = if (b) {
22-
{ str, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str2<!> -> "this" }
22+
{ str, str2 -> "this" }
2323
} else {
24-
{ str, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str2<!> -> "this" }
24+
{ str, str2 -> "this" }
2525
}
2626

2727
val x2: String.() -> String = if (b) {
@@ -31,9 +31,9 @@ fun test_3(b: Boolean) {
3131
}
3232

3333
val x3: String.() -> String = if (b) {
34-
<!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>x<!> -> "x" }<!>
34+
{ x -> "x" }
3535
} else {
36-
<!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>x<!> -> "x" }<!>
36+
{ x -> "x" }
3737
}
3838
}
3939

compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.fir.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN_PIPELINE_TILL: FRONTEND
1+
// RUN_PIPELINE_TILL: BACKEND
22
// DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_ANONYMOUS_PARAMETER
33

44
fun <T> select(vararg x: T) = x[0]
@@ -9,9 +9,9 @@ fun main() {
99
val x3: () -> String = if (true) {{ -> "this" }} else {{ -> "this" }}
1010
val x4: String.() -> String = if (true) {{ str: String -> "this" }} else {{ str: String -> "this" }}
1111
val x41: String.(String) -> String = if (true) {{ str: String, str2: String -> "this" }} else {{ str: String, str2: String -> "this" }}
12-
val x42: String.(String) -> String = if (true) {{ str, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str2<!> -> "this" }} else {{ str, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str2<!> -> "this" }}
13-
val x5: String.() -> String = if (true) {<!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str<!> -> "this" }<!>} else {<!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str<!> -> "this" }<!>}
14-
val x6: String.() -> String = <!INITIALIZER_TYPE_MISMATCH!>if (true) {<!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>str<!> -> "this" }<!>} else {{ "this" }}<!>
12+
val x42: String.(String) -> String = if (true) {{ str, str2 -> "this" }} else {{ str, str2 -> "this" }}
13+
val x5: String.() -> String = if (true) {{ str -> "this" }} else {{ str -> "this" }}
14+
val x6: String.() -> String = if (true) {{ str -> "this" }} else {{ "this" }}
1515
val x7: String.() -> String = select({ -> this }, { -> this })
1616
val x8: String.() -> String = select({ this }, { this })
1717
}

compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN_PIPELINE_TILL: FRONTEND
1+
// RUN_PIPELINE_TILL: BACKEND
22
// DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_ANONYMOUS_PARAMETER
33

44
fun <T> select(vararg x: T) = x[0]

compiler/testData/diagnostics/tests/inference/lambdasWithExplicitParametersViaReceivers.fir.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
// ISSUE: KT-81115
33

44
val l1: String.() -> String = fun(x: String) = ""
5-
val l2: String.() -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String -> "" }<!>
5+
val l2: String.() -> String = { x: String -> "" }
66

77
val l3: String.() -> String = fun(x) = x
8-
val l4: String.() -> String = <!INITIALIZER_TYPE_MISMATCH!>{ <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>x<!> -> x }<!>
8+
val l4: String.() -> String = { x -> x }
99

1010
val l5: String.(Int) -> String = fun(x: String, y) = ""
11-
val l6: String.(Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, <!CANNOT_INFER_VALUE_PARAMETER_TYPE!>y<!> -> "" }<!>
11+
val l6: String.(Int) -> String = { x: String, y -> "" }
1212

1313
val w1: String.(Int, Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>fun(x: String, y) = ""<!>
1414
val w2: String.(Int, Int) -> String = <!INITIALIZER_TYPE_MISMATCH!>{ x: String, y -> "" }<!>

0 commit comments

Comments
 (0)