Auto-casting not working for lists

The following code should be self explaining. I’ve got a list of Test objects, the function test get’s a downcasted test object supplied. Since list can only have test objects, the object must be a Test. But kotlin doesn’t recognize this.

val list = mutableListOf<Test>(Test())

fun main() = test(list[0])

fun test(obj: Any) {
    if (obj in list) { // No auto casting :c
        obj.print() // Fails
        (obj as Test).print() // Workaround
    }
}

class Test {
    fun print() = println("Hello World!")
}

You should check type before.

MutableList<Test> can be cast to Iterable<Any>.
The type of obj is Any, so obj in list equals to list.contains<Any>(obj).

You can see that the contains method below not the same.

image

Anything can be cast to Any. MutableList should (is intended to) only contain Test objects, so when the list contains an object, it should be Test.

The contains method your called is not belong to List.

And? This doesn’t change anything. When an object is in MutableList<Test> then the object is Test.

The Kotlin compiler simply doesn’t know that List<T>.contains(x) == true implies that x is T. I’m sure that could be somehow added with contracts, but currently, the compiler only recognises simple conditions and casts like is, as? and so on.

I was pretty sure that constraints are already used in the stdlib for things like this. Seems like i was wrong. Thanks for the clarification tho.

The reason why contains does not yet use contracts is that it’s a member function of List and contracts only work for top level functions right now. I guess this will be added once contracts are expanded to work with member functions.

Okay, I hope they will fix this when constracts are stable.