How to make type inference work for instances adhering to nested generic interfaces?

Viewed 49

This minimal example

interface Foo<T> {
    fun foobinate(value: T)
}

interface Bar<T>

class AFoo<T> : Foo<T> {
    override fun foobinate(value: T) {}
}

class ABar<T> : Bar<T>

fun <T> doSomething(foo: Foo<Bar<T>>, x: Bar<T>) {
    foo.foobinate(x)
}

fun main() {
    val foo = AFoo<ABar<Int>>()
    doSomething(foo, ABar<Int>())
}

gives an error for the doSomething line:

Type mismatch: inferred type is AFoo<ABar<Int>> but Foo<Bar<Int>> was expected

Is there any way to make it work, or is there some conceptual thing standing in the way?

1 Answers

Declaring doSomething like this should work

fun <A : Bar<*>> doSomething(foo: Foo<A>, x: A) {
    foo.foobinate(x)
}

This way, you ensure that x is of the specific type that Foo accepts, since both Foo and Bar have invariant type parameters.

This here doesn't work because the subclass of Bar<T> that becomes the T in Foo<T> gets and the subclass of Bar<T> of which x is an instance can be 2 different types.

fun <T, A : Bar<T>> doSomething(foo: Foo<Bar<T>>, x: Bar<T>) {
    foo.foobinate(x)
}
Related