[NI] Fix resolve of lambdas with expected function type with receiver
#KT-30245
This commit is contained in:
+10
-5
@@ -130,27 +130,32 @@ private fun extractLambdaInfoFromFunctionalType(
|
|||||||
|
|
||||||
// Extracting parameters and receiver type, taking into account the actual lambda definition and expected lambda type
|
// Extracting parameters and receiver type, taking into account the actual lambda definition and expected lambda type
|
||||||
val (parameters, receiver) = when {
|
val (parameters, receiver) = when {
|
||||||
argumentAsFunctionExpression != null ->
|
argumentAsFunctionExpression != null -> {
|
||||||
// lambda has explicit functional type - use types from it if available
|
// lambda has explicit functional type - use types from it if available
|
||||||
(parametersTypes?.mapIndexed { index, type ->
|
(parametersTypes?.mapIndexed { index, type ->
|
||||||
type.orExpected(index)
|
type.orExpected(index)
|
||||||
} ?: emptyList()) to argumentAsFunctionExpression.receiverType
|
} ?: 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
|
// 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
|
// 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 ->
|
(parametersTypes?.mapIndexed { index, type ->
|
||||||
type.orExpected(index)
|
type.orExpected(index)
|
||||||
} ?: expectedParameters.map { it.type.unwrap() }) to expectedReceiver
|
} ?: expectedParameters.map { it.type.unwrap() }) to expectedReceiver
|
||||||
|
}
|
||||||
|
|
||||||
(parametersTypes?.size ?: 0) - expectedParameters.size == 1 && receiverFromExpected -> {
|
(parametersTypes?.size ?: 0) - expectedParameters.size == 1 && receiverFromExpected -> {
|
||||||
// one "missing" parameter in the expected parameters - first lambda parameter should be mapped to expected receiver
|
// 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
|
// TODO: same "this" or "it" case from above could be applicable here as well
|
||||||
|
|
||||||
(parametersTypes?.mapIndexed { index, type ->
|
(parametersTypes?.mapIndexed { index, type ->
|
||||||
type ?: run {
|
type ?: run {
|
||||||
if (index == 0) expectedReceiver?.unwrap()
|
expectedParameters.getOrNull(index)?.type?.unwrap()
|
||||||
else expectedParameters.getOrNull(index - 1)?.type?.unwrap()
|
|
||||||
} ?: expectedType.builtIns.nullableAnyType
|
} ?: expectedType.builtIns.nullableAnyType
|
||||||
} ?: expectedParameters.map { it.type.unwrap() }) to null
|
} ?: expectedParameters.map { it.type.unwrap() }) to expectedReceiver?.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
(parametersTypes?.mapIndexed { index, type ->
|
(parametersTypes?.mapIndexed { index, type ->
|
||||||
type.orExpected(index)
|
type.orExpected(index)
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
// !WITH_NEW_INFERENCE
|
||||||
fun foo(<!UNUSED_PARAMETER!>f<!>: String.() -> Int) {}
|
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 f10 = W1(fun Int.(): Int = this) // oi+ ni+
|
||||||
val g10: E0 = id(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 i11: E0 = id { i: Int -> i } // o1+ ni+
|
||||||
val w12 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni+
|
val w12 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni-
|
||||||
val i12: E0 = id { i -> i } // oi- ni+
|
val i12: E0 = id { i -> i } // oi- ni-
|
||||||
val j12 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { i -> i } // oi- ni+
|
val j12 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { i -> i } // oi- ni-
|
||||||
|
|
||||||
// yet unsupported cases - considering lambdas as extension ones unconditionally
|
// yet unsupported cases - considering lambdas as extension ones unconditionally
|
||||||
// val w13 = W1 { it } // this or it: oi- ni-
|
// 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 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 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 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 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 w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni-
|
||||||
val i29: E1 = id { 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)
|
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ fun test1() { // to extension lambda 0
|
|||||||
val f10 = W1(fun Int.(): Int = this) // oi+ ni+
|
val f10 = W1(fun Int.(): Int = this) // oi+ ni+
|
||||||
val g10: E0 = id(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 i11: E0 = id { i: Int -> i } // o1+ ni+
|
||||||
val w12 = W1 { 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 { i -> 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> { i -> 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
|
// yet unsupported cases - considering lambdas as extension ones unconditionally
|
||||||
// val w13 = W1 { it } // this or it: oi- ni-
|
// 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 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 i27: E1 = id { i, s: String -> i + s.length } // overload oi- ni-
|
||||||
|
|
||||||
val w28 = W2 { i: Int, s -> 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 = id { i: Int, s -> i + s.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 { i: Int, s: String -> i + s.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+
|
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)
|
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package
|
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 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 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 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>>
|
public typealias Array2D</*0*/ T> = kotlin.Array<kotlin.Array<T>>
|
||||||
|
|||||||
Reference in New Issue
Block a user