[NI] Fix resolve of lambdas with expected function type with receiver

#KT-30245
This commit is contained in:
Dmitriy Novozhilov
2020-01-15 17:24:25 +03:00
parent 7733611c47
commit a3037a081e
5 changed files with 26 additions and 21 deletions
@@ -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)
@@ -1,3 +1,3 @@
// !WITH_NEW_INFERENCE
fun foo(<!UNUSED_PARAMETER!>f<!>: String.() -> Int) {}
val test = foo(<!OI;TYPE_MISMATCH!>fun () = <!UNRESOLVED_REFERENCE!>length<!><!>)
val test = foo(<!TYPE_MISMATCH!>fun <!NI;EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = <!UNRESOLVED_REFERENCE!>length<!><!>)
@@ -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 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni+
val i12: E0 = id { i -> i } // oi- ni+
val j12 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { i -> i } // oi- ni+
val w12 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni-
val i12: E0 = id { i -> i } // oi- ni-
val j12 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { 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 = <!INAPPLICABLE_CANDIDATE!>W2<!> { i: Int, s -> i <!AMBIGUITY!>+<!> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi- ni+
val i28: E1 = id { i: Int, s -> i <!AMBIGUITY!>+<!> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi- ni+
val w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni+
val w28 = <!INAPPLICABLE_CANDIDATE!>W2<!> { i: Int, s -> i <!AMBIGUITY!>+<!> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi- ni-
val i28: E1 = id { i: Int, s -> i <!AMBIGUITY!>+<!> s.<!UNRESOLVED_REFERENCE!>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)
+7 -7
View File
@@ -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 <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>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<E0> { i -> i } // oi- ni+
val w12 = W1 <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE, EXPECTED_PARAMETERS_NUMBER_MISMATCH!>i<!> -> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>i<!> }<!> // oi- ni-
val i12: E0 = id <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE, EXPECTED_PARAMETERS_NUMBER_MISMATCH!>i<!> -> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>i<!> }<!> // oi- ni-
val j12 = id<E0> <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE, EXPECTED_PARAMETERS_NUMBER_MISMATCH!>i<!> -> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>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 <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!><!EXPECTED_PARAMETER_TYPE_MISMATCH!>i: Int<!>, <!CANNOT_INFER_PARAMETER_TYPE!>s<!><!> -> i <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>s<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>length<!> }<!> // oi- ni-
val i28: E1 = <!TYPE_MISMATCH!>id <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!><!EXPECTED_PARAMETER_TYPE_MISMATCH!>i: Int<!>, <!CANNOT_INFER_PARAMETER_TYPE!>s<!><!> -> i <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>s<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>length<!> }<!><!> // oi- ni-
val w29 = W2 <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!><!EXPECTED_PARAMETER_TYPE_MISMATCH!>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)
@@ -1,7 +1,7 @@
package
public fun bar1(/*0*/ a: Array2D<kotlin.Int> /* = kotlin.Array<kotlin.Array<kotlin.Int>> */): Array2D<out kotlin.Number> /* = kotlin.Array<kotlin.Array<out kotlin.Number>> */
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<out kotlin.Number> /* = kotlin.Array<kotlin.Array<out kotlin.Number>> */): Array2D<out kotlin.Number> /* = kotlin.Array<kotlin.Array<out kotlin.Number>> */
public fun </*0*/ T> foo2(/*0*/ m: TMap<T> /* = kotlin.collections.Map<T, T> */): TMap<T> /* = kotlin.collections.Map<T, T> */
public typealias Array2D</*0*/ T> = kotlin.Array<kotlin.Array<T>>