// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST import kotlin.reflect.KFunction1 fun withOverload(i: Int) {} fun withOverload(s: String) {} fun takeInt(i: Int) {} fun takeNumber(i: Number) {} fun id(x: K): K = x fun id1(x: K): K = x fun id2(x: L): L = x fun selectWithInv(x: T, y: Inv): T = TODO() fun select(vararg x: T) = x[0] fun takeLambdas(vararg x: (T) -> Unit) = x[0] fun takeLambdasWithDirectlyDependentTypeParameters(x: (T) -> Unit, y: (R) -> Unit, z: (L) -> Unit) = x fun takeLambdasWithInverselyDependentTypeParameters(x: (T) -> Unit, y: (R) -> Unit, z: (L) -> Unit) = x fun takeInterdependentLambdas(x: (T) -> R, y: (R) -> T) {} fun takeDependentLambdas(x: (T) -> Int, y: (Int) -> T) {} class Inv(val x: T) fun Unit> selectNumber(arg1: T, arg2: T, arg3: T) = arg1 fun Unit> selectFloat(arg1: T, arg2: T, arg3: T) = arg2 fun Unit> selectA(arg1: T, arg2: T, arg3: T) = arg2 fun Unit> selectB(arg1: T, arg2: T, arg3: T) = arg2 fun Unit> selectC(arg1: T, arg2: T, arg3: T) = arg2 interface A class B: A class C: A class A2: Function3 { override fun invoke(p1: Int, p2: String, p3: Float): Float = 4f } class A3: KFunction1 { override fun invoke(p1: Number): String = TODO() override val name: String = TODO() fun foo1(x: Int) {} fun foo1(x: Any?) {} companion object { fun foo2(x: Int) {} fun foo2(x: Any?) {} } } class A4: Function1 { override fun invoke(p1: Int): Float = TODO() } class A5: Function2 { override fun invoke(p1: K, p2: Q): Float = 5f } fun main() { // Inferring lambda parameter types by other lambda explicit parameters; expected type is type variable select(id1 { x -> x.inv() }, id2 { x: Int -> }) select(id1 { it.inv() }, id2 { x: Int -> }) selectWithInv(id1 { it.inv() }, id2(Inv { x: Int -> })) select(id1 { it.inv() }, id1 { x: Number -> TODO() }, id1(id2 { x: Int -> x })) select(id1 { it.inv() }, id1 { x: Number -> TODO() }, id1(id2(::takeInt))) select(id1 { x: Inv -> TODO() }, id1 { ")!>it.x.inv() }, id1 { x: Inv -> TODO() }) select(id1 { & Inv")!>it }, id1 { x: Inv -> TODO() }, id1 { x: Inv -> TODO() }) select(id(id2 { it.inv() }), id(id { x: Int -> x })) // Disambiguating callable references by other callable references without overloads ")!>select(id(::withOverload), id(::takeInt), id(id(::takeNumber))) // Interdependent lambdas by input-output types aren't supported takeInterdependentLambdas({}, {}) takeInterdependentLambdas({ it }, { 10 }) takeInterdependentLambdas({ 10 }, { it }) takeInterdependentLambdas({ 10 }, { x -> x }) takeInterdependentLambdas({ x -> 10 }, { it }) takeInterdependentLambdas({ it }, { x -> 10 }) // Dependent lambdas by input-output types takeDependentLambdas({ it }, { it }) takeDependentLambdas({ it.length }, { "it" }) takeDependentLambdas({ it; 10 }, { }) // Inferring lambda parameter types by anonymous function parameters select({ it }, fun(x: Int) = 1) // Inferring lambda parameter types by other lambda explicit parameters (lower constraints) and expected type (upper constraints) val x5: (Int) -> Unit = select({ it }, { x: Number -> Unit }) // Inferring lambda parameter types by other lambda explicit parameters (lower constraints) and specified type arguments (equality constraints) select(id { it }, id(id<(Int) -> Unit> { x: Number -> Unit })) // Inferring lambda parameter types by specified type arguments (equality constraints) of other lambdas select(id { it.inv() }, id<(Int) -> Unit> { }) select( id { x, y -> x.inv() + y.toByte() }, id<(Int, Number) -> Int> { x, y -> x.inv() }, {} as (Number, Number) -> Int ) // Inferring lambda parameter types by a few expected types (a few upper constraints) val x7: (Int) -> Unit = ")!>selectNumber(id {}, id {}, id {}) val x8: (Int) -> Unit = selectNumber(id { x -> x }, id { x -> }, id { x -> }) val x9: (Int) -> Unit = selectNumber(id { }, id { x -> }, id { it }) val x10: (Int) -> Unit = selectFloat(id { }, id { x -> }, id { ")!>it }) val x11: (B) -> Unit = selectC(id { }, id { x -> x }, id { it }) // Inferring lambda parameter types by expected types (upper constraints) and other lambda explicit parameters (lower constraints) /* * Upper constraint is less specific than lower (it's error): * K <: (A) -> Unit -> TypeVariable(_RP1) >: A * K >: (C) -> TypeVariable(_R) -> TypeVariable(_RP1) <: C */ val x12 = selectC(id { it }, id { x: B -> }) val x13 = selectA(id { it }, id { x: C -> }) val x14 = selectC(id { it }, id { x: A -> }, { x -> x }) val x15 = selectC(id { it }, { x: A -> }, id { x -> x }) /* * Two upper constraints and one lower * K <: (C) -> Unit -> TypeVariable(_RP1) >: C * K <: (B) -> Unit -> TypeVariable(_RP1) >: B * K >: (A) -> TypeVariable(_R) -> TypeVariable(_RP1) <: A * K == intersect(CST(C, B), A) == A */ val x16: (C) -> Unit = selectB(id { it }, { x -> }, id { x: A -> x }) // Inferring lambda parameter types by expected types (upper constraints) and specified type arguments (equality constraints) of other lambdas /* * two upper constraints and one equality (it's error) * K <: (C) -> Unit -> TypeVariable(_RP1) >: C * K == (B) -> Unit -> TypeVariable(_RP1) == B */ val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) // Resolution of extension/non-extension functions combination val x19: String.() -> Unit = select(")!>id { this }, ")!>id(fun(x: String) {})) val x20: String.() -> Unit = select(")!>{ this }, (fun(x: String) {})) val x21: String.() -> Unit = select(")!>id(fun(x: String) {}), ")!>id(fun(x: String) {})) select(id Unit>(fun(x: String) {}), ")!>id(fun(x: String) {})) select(")!>id(fun String.(x: String) {}), ")!>id(fun(x: String, y: String) {})) select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x: String -> this }) select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x -> this }) select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x: String, y: String -> x }) // Convert to extension lambda is impossible because the lambda parameter types aren't specified explicitly select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x, y -> x }) select(id(id(fun(x: String, y: String) { }), fun String.(x: String) {}), { x, y -> x }) val x26: Int.(String) -> Int = fun (x: String) = 10 // it must be error, see KT-38439 // Receiver must be specified in anonymous function declaration val x27: Int.(String) -> Int = id(fun (x: String) = 10) select(id Unit> {}, { x: Int, y: String -> x }) // Inferring lambda parameter types by partially specified parameter types of other lambdas select(id { x, y -> x.inv() + y.toByte() }, { x: Int, y -> y.toByte() }, { x, y: Number -> x.inv() }) select(id { x, y -> x.inv() + y.toByte() }, id { x: Int, y -> y.toByte() }, id { x, y: Number -> x.inv() }) select({ x, y -> x.inv() + y.toByte() }, id { x: Int, y -> y.toByte() }, id { x, y: Number -> x.inv() }) // Inferring lambda parameter types by other specified lambda parameters; expected type is a functional type with type variables in parameter types takeLambdas({ it }, { x: Int -> }, { x: Nothing -> x }) takeLambdas({ it }, { } as (Int) -> Unit, { x: Nothing -> x }) takeLambdas({ it }, { } as (Nothing) -> Unit, { x: Int -> x }) takeLambdas({ it }, { } as (Int) -> Unit, { } as (Nothing) -> Unit) // Inferring lambda parameter types by other specified lambda parameters; expected type is a functional type with type variables in parameter types; dependent type parameters takeLambdasWithDirectlyDependentTypeParameters({ it }, { it }, { x: Int -> x }) takeLambdasWithDirectlyDependentTypeParameters({ it }, { x: Number -> x }, { x: Int -> x }) takeLambdasWithInverselyDependentTypeParameters({ it }, { it }, { x: Int -> x }) /* * Interesting test case: variable can be fixed to different types randomly (`Int` or `Number`; it depends on variable fixation order) * if in `TypeVariableDependencyInformationProvider` `hashSet` instead of `linkedSet` for `deepTypeVariableDependencies` and `shallowTypeVariableDependencies` will be used */ takeLambdasWithInverselyDependentTypeParameters({ it }, { x: Number -> x }, { x: Int -> x }) // Inferring lambda parameter types by subtypes of functional type ")!>select(A2(), { a, b, c -> a; b; c }) ")!>select(A3(), { it }, { a -> a }) ")!>select(A3(), ")!>A3::foo1) // Should be error as `A3::foo1` is `KFunction2`, but the remaining arguments are `KFuncion1` or `Function1` ")!>select(A3(), ")!>A3::foo1, { a -> a }, { it -> it }) // It's OK because `A3::foo2` is from companion of `A3` ")!>select(A3(), ")!>A3::foo2, { a -> a }, { it -> it }) & java.io.Serializable>")!>select(A4(), { x: Number -> "" }) & java.io.Serializable>")!>select(A5(), { x: Number, y: Int -> "" }) ")!>select(A2(), id { a, b, c -> a; b; c }) ")!>select(id(A3()), { it }, { a -> a }) ")!>select(A3(), id(")!>A3::foo1)) ")!>select(A3(), ")!>A3::foo1, id { a -> a }, { it -> it }) ")!>select(A3(), ")!>A3::foo1, { a -> a }, id { it -> it }) ")!>select(id(A3()), id(")!>A3::foo1), { a -> a }, { it -> it }) ")!>select(id(A3()), id(")!>A3::foo1), { a -> a }, id { it -> it }) // If lambdas' parameters are specified explicitly, we don't report an error, because there is proper CST – Function ")!>select(id(A3()), id(")!>A3::foo1), { a: Number -> a }) ")!>select(id(A3()), id(")!>A3::foo1), id { a: Number -> a }) ")!>select(A4(), id { x: Number -> x }) >")!>select(id(A5()), id { x: Number, y: Int -> x;y }) >")!>select(id(A5()), id { x, y -> x;y }) >")!>select(id(")!>A5()), id { x: Number, y: Int -> x;y }) val x55: Function2 = select(id(A5()), id { x, y -> x;y; 1f }) // Diffrerent lambda's parameters with proper CST ")!>select({ x: Int -> }, { x: String -> }) ")!>select({ x: Int -> }, { x: Int, y: Number -> }) ")!>select(id { x: Int -> }, { x: String -> }) ")!>select({ x: Int -> }, id { x: Int, y: Number -> }) ")!>select(id { x: Int -> }, id { x: String -> }) ")!>select(id { x: Int -> }, id { x: Int, y: Number -> }) & java.io.Serializable>")!>select({ x: Int -> 1 }, { x: String -> "" }) >")!>select({ x: Int -> 1 }, { x: Int, y: Number -> 1f }) & java.io.Serializable>>")!>select(id { x: Int -> Inv(10) }, { x: String -> Inv("") }) ")!>select({ x: Int -> TODO() }, id { x: Int, y: Number -> Any() }) ")!>select(id { x: Int -> null }, id { x: String -> "" }) ")!>select(id { x: Int -> 10 }, id { x: Int, y: Number -> TODO() }) val x68: String.(String) -> String = select(id { x: String, y: String -> "10" }, id { x: String, y: String -> "TODO()" }) // Anonymous functions val x69: (C) -> Unit = selectB({ it }, { }, id(fun (x) { x })) select(id1(fun(it) { it.inv() }), id1 { x: Number -> TODO() }, id1(id2(::takeInt))) select(id(fun (it) { it }), id(id<(Int) -> Unit> { x: Number -> Unit })) select(id(fun (it) { it.inv() }), id<(Int) -> Unit> { }) 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 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 }) }