Kotlin is "widening" the type here because the value type parameter (i.e. the second type parameter) of KProperty1
is defined with keyword out
which makes that parameter covariant.
This means that for instance KProperty1<User, String>
is a subtype of KProperty1<User, Any>
, and hence User::name
which is presumably a KProperty1<User, String>
, can also be seen as a special case of KProperty<User, Any>
. Therefore, it is totally legal to call myFunction<User,Any>(User::name, 123)
.
The logic behind this can be derived from the name of the out
keyword: It is expected that the typed parameter is only used in "out position" of any function call. In the case of KProperty1
this makes sense, because it is the type of the return value of the property. When you get a value from a KProperty1<K, V>
, that value is of type V
and thus it can be used anywhere where it is okay to have some supertype of V
.
This should only be a problem, if you want to use the value in the "in position" of some function, for instance, if you want to write a function that takes a value of type V
and store it in a KProperty1<K, V>
.
If this is what you want, you are lucky, because you can and should just use KMutableProperty1<K,V>
where the value parameter does not have an out
keyword which means that it is invariant. Also, that interface allows you to put the value into the property.
Changing your function definition to
fun <R,F> myFunction(prop: KMutableProperty1<R, F>, value:F) {}
makes that the compiler allows myFunction(User::name, "Alejandro")
, but it complains on myFunction(User::name, 123)
.
See also: Kotlin documentation on Variance