miguel
miguel

Reputation: 16600

Type inference only works for extension function

The following code works fine and the call to the foo.get() extension function returns the correct type BarImpl.

open class Bar
class BarImpl: Bar()

class Foo<T : Bar> 

inline fun <reified T : Bar> Foo<T>.get(): T {
    return SomeMap(this).get(T::class)
}

class Activity {
    lateinit var foo: Foo<BarImpl>
    val barImpl = foo.get()
}

But when I try to move Foo<T>.get() into the class the type inference fails

class Foo<T : Bar> {
    inline fun <reified T : Bar> get(): T {
        return SomeMap(this).get(T::class)
    }
}

class Activity {
    lateinit var foo: Foo<BarImpl>
    val barImpl = foo.get()
}

error: type inference failed: Not enough information to infer parameter T in inline fun get(): T Please specify it explicitly.

   val vm = foo.get()
                ^

How can I move the function into the class?

Upvotes: 1

Views: 97

Answers (1)

IlyaMuravjov
IlyaMuravjov

Reputation: 2502

The extension function returns the result of the Foo type parameter. So the result type can be inferred from the receiver type.

And the member function result type has nothing in common with Foo type parameter except the name, which means nothing for a compiler. You can see that T in method and T in class are different types by writing and compiling the following code:

Foo<BarImpl>().get<BarImpl2>()

If you want to make get to be a member function which returns the result of Foo type parameter, you should remove type parameter from function and inject class instance via the constructor:

class Foo<T : Bar>(private val clazz: KClass<T>) {
    fun get(): T {
        return SomeMap(this).get(clazz)
    }

    companion object {
        inline operator fun <reified T : Bar> invoke() = Foo(T::class)
    }
}

Upvotes: 4

Related Questions