From a3037a081ec9da48e63fb57def0d368e5bec1859 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 15 Jan 2020 17:24:25 +0300 Subject: [PATCH] [NI] Fix resolve of lambdas with expected function type with receiver #KT-30245 --- .../calls/components/PostponeArgumentsChecks.kt | 15 ++++++++++----- .../ReceiverByExpectedType.kt | 2 +- .../diagnostics/tests/regressions/kt30245.fir.kt | 14 +++++++------- .../diagnostics/tests/regressions/kt30245.kt | 14 +++++++------- ...ximationInTypeAliasArgumentSubstitution.ni.txt | 2 +- 5 files changed, 26 insertions(+), 21 deletions(-) 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 517df0e2b9d..90bd58a8ab9 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 @@ -130,27 +130,32 @@ private fun extractLambdaInfoFromFunctionalType( // Extracting parameters and receiver type, taking into account the actual lambda definition and expected lambda type val (parameters, receiver) = when { - argumentAsFunctionExpression != null -> + argumentAsFunctionExpression != null -> { // lambda has explicit functional type - use types from it if available (parametersTypes?.mapIndexed { index, type -> type.orExpected(index) } ?: emptyList()) to argumentAsFunctionExpression.receiverType - (parametersTypes?.size ?: 0) == expectedParameters.size && receiverFromExpected -> + } + + (parametersTypes?.size ?: 0) == expectedParameters.size && receiverFromExpected -> { // expected type has receiver, but arguments sizes are the same in actual and expected, so assuming missing (maybe unused) receiver in lambda // TODO: in case of implicit parameters in lambda ("this" and "it") this case assumes "this", probably we should generate two possible overloads and choose among them later (parametersTypes?.mapIndexed { index, type -> type.orExpected(index) } ?: expectedParameters.map { it.type.unwrap() }) to expectedReceiver + } + (parametersTypes?.size ?: 0) - expectedParameters.size == 1 && receiverFromExpected -> { // one "missing" parameter in the expected parameters - first lambda parameter should be mapped to expected receiver // TODO: same "this" or "it" case from above could be applicable here as well + (parametersTypes?.mapIndexed { index, type -> type ?: run { - if (index == 0) expectedReceiver?.unwrap() - else expectedParameters.getOrNull(index - 1)?.type?.unwrap() + expectedParameters.getOrNull(index)?.type?.unwrap() } ?: expectedType.builtIns.nullableAnyType - } ?: expectedParameters.map { it.type.unwrap() }) to null + } ?: expectedParameters.map { it.type.unwrap() }) to expectedReceiver?.unwrap() } + else -> (parametersTypes?.mapIndexed { index, type -> type.orExpected(index) diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt b/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt index bad2c25b52f..fc4d953d716 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt @@ -1,3 +1,3 @@ // !WITH_NEW_INFERENCE fun foo(f: String.() -> Int) {} -val test = foo(fun () = length) \ No newline at end of file +val test = foo(fun () = length) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt index 4c0af7721fe..70b7f9955db 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt @@ -42,11 +42,11 @@ fun test1() { // to extension lambda 0 val f10 = W1(fun Int.(): Int = this) // oi+ ni+ val g10: E0 = id(fun Int.(): Int = this) // oi+ ni+ - val w11 = W1 { i: Int -> i } // oi- ni+ + val w11 = W1 { i: Int -> i } // oi- ni- val i11: E0 = id { i: Int -> i } // o1+ ni+ - val w12 = W1 { i -> i } // oi- ni+ - val i12: E0 = id { i -> i } // oi- ni+ - val j12 = id { i -> i } // oi- ni+ + val w12 = W1 { i -> i } // oi- ni- + val i12: E0 = id { i -> i } // oi- ni- + val j12 = id { i -> i } // oi- ni- // yet unsupported cases - considering lambdas as extension ones unconditionally // val w13 = W1 { it } // this or it: oi- ni- @@ -78,9 +78,9 @@ fun test2() { // to extension lambda 1 // val w27 = W2 { i, s: String -> i + s.length } // overload oi- ni- // val i27: E1 = id { i, s: String -> i + s.length } // overload oi- ni- - val w28 = W2 { i: Int, s -> i + s.length } // oi- ni+ - val i28: E1 = id { i: Int, s -> i + s.length } // oi- ni+ - val w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni+ + val w28 = W2 { i: Int, s -> i + s.length } // oi- ni- + val i28: E1 = id { i: Int, s -> i + s.length } // oi- ni- + val w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni- val i29: E1 = id { i: Int, s: String -> i + s.length } // oi+ ni+ // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.kt index 6788b5d2688..3cb29c2483b 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.kt @@ -42,11 +42,11 @@ fun test1() { // to extension lambda 0 val f10 = W1(fun Int.(): Int = this) // oi+ ni+ val g10: E0 = id(fun Int.(): Int = this) // oi+ ni+ - val w11 = W1 { i: Int -> i } // oi- ni+ + val w11 = W1 { i: Int -> i } // oi- ni- val i11: E0 = id { i: Int -> i } // o1+ ni+ - val w12 = W1 { i -> i } // oi- ni+ - val i12: E0 = id { i -> i } // oi- ni+ - val j12 = id { i -> i } // oi- ni+ + val w12 = W1 { i -> i } // oi- ni- + val i12: E0 = id { i -> i } // oi- ni- + val j12 = id { i -> i } // oi- ni- // yet unsupported cases - considering lambdas as extension ones unconditionally // val w13 = W1 { it } // this or it: oi- ni- @@ -78,9 +78,9 @@ fun test2() { // to extension lambda 1 // val w27 = W2 { i, s: String -> i + s.length } // overload oi- ni- // val i27: E1 = id { i, s: String -> i + s.length } // overload oi- ni- - val w28 = W2 { i: Int, s -> i + s.length } // oi- ni+ - val i28: E1 = id { i: Int, s -> i + s.length } // oi- ni+ - val w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni+ + val w28 = W2 { i: Int, s -> i + s.length } // oi- ni- + val i28: E1 = id { i: Int, s -> i + s.length } // oi- ni- + val w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni- val i29: E1 = id { i: Int, s: String -> i + s.length } // oi+ ni+ // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) diff --git a/compiler/testData/diagnostics/tests/typealias/noApproximationInTypeAliasArgumentSubstitution.ni.txt b/compiler/testData/diagnostics/tests/typealias/noApproximationInTypeAliasArgumentSubstitution.ni.txt index 9a8e2305c9a..3d38fa59b19 100644 --- a/compiler/testData/diagnostics/tests/typealias/noApproximationInTypeAliasArgumentSubstitution.ni.txt +++ b/compiler/testData/diagnostics/tests/typealias/noApproximationInTypeAliasArgumentSubstitution.ni.txt @@ -1,7 +1,7 @@ package public fun bar1(/*0*/ a: Array2D /* = kotlin.Array> */): Array2D /* = kotlin.Array> */ -public fun bar2(/*0*/ m: TMap<*> /* = kotlin.collections.Map<*, *> */): kotlin.collections.Map<*, *> +public fun bar2(/*0*/ m: TMap<*> /* = kotlin.collections.Map<*, *> */): kotlin.collections.Map<*, kotlin.Any?> public fun foo1(/*0*/ a: Array2D /* = kotlin.Array> */): Array2D /* = kotlin.Array> */ public fun foo2(/*0*/ m: TMap /* = kotlin.collections.Map */): TMap /* = kotlin.collections.Map */ public typealias Array2D = kotlin.Array>