I believe this is expected and correct behavior.
eq
function is a generic function, so i’ts actual type parameters can be either specified at the call site or inferred if possible.
`KProperty`` is defined as follows:
interface KProperty1<T, out V>
Note the V
parameter is covariant. As stated in Kotlin Generics docs:
when a type parameter T of a class C is declared out, it may occur only in out-position in the members of C, but in return C<Base>
can safely be a supertype of C<Derived>
.
Thus, KProperty1<A, Any>
is a supertype of KProperty1<A, Int>
.
As for KProperty<A, Any>
the parameter of eq
method is Any
, it can accept String
.
Of course it’s possible to call method of base class on an instance of derived class, so as a result
prop.eq(value)
is inferred to
prop.eq<A, Any>(value)
Note that if the type parameter was contravariant, valid types for method call could still be inferred. Only the invariant version would not compile - see:
class Invariant<T>
class Covariant<out T>
class Contravariant<in T>
inline fun <reified T> Invariant<T>.inferType(x: T): String = "${T::class}"
inline fun <reified T> Covariant<T>.inferType(x: T): String = "${T::class}"
inline fun <reified T> Contravariant<T>.inferType(x: T): String = "${T::class}"
fun main() {
val invariant = Invariant<Int>()
println(invariant.inferType(1)) // kotlin.Int
// println(invariant.eq("foo")) // does not compile!
val covariant = Covariant<Int>()
println(covariant.inferType(1)) // kotlin.Int
println(covariant.inferType("foo")) // kotlin.Any
val contravariant = Covariant<Int>()
println(contravariant.inferType(1)) // kotlin.Int
println(contravariant.inferType("foo")) // kotlin.Any
}