Jaap Beetstra
05/31/2024, 10:10 AMinterface Intf
class Clz : Intf
inline fun <reified T> showType(noinline lmb: (T) -> T) {
println(typeOf<T>())
}
fun main() {
showType { _: Intf -> Clz() } // 'Clz', why ?!
showType { _: Intf -> Clz() as Intf } // 'Intf', as expected
}
(IntelliJ IDEA marks the as Intf
in the second call with a ‘No cast needed’ warning)Sam
05/31/2024, 10:20 AMT
is inferred from the lambda signature. In the first example, the lambda function has type (Intf) -> Clz
. We need to infer a value for T
such that (Intf) -> Clz
satisfies (T) -> T
. Functions are contravariant on input types and covariant on output types, so for (Intf) -> Clz
to be a subtype of (T) -> T
, Intf
must be a supertype of T
and Clz
must be a subtype of T
. The type that satisfies those constraints is Clz
.Sam
05/31/2024, 10:22 AM(Intf) -> Intf
), so that other return values would also be allowed.Sam
05/31/2024, 10:24 AMT
is inferred. I don't think the second type inference can feed back into the first one in any way.Jaap Beetstra
06/01/2024, 8:20 AM