Search code examples
functionoperator-overloadingkotlinjvm-languagesreification

Kotlin: UnsupportedOperationException for reified generic with get/set operator


I am trying to convert the functions read and write in my library to operator functions get and set, respectively. My functions use a reified generic type, they are also inline methods. (You can see my library here.)

The compiler has no issue letting me pass and I don't see why using non-operator functions the inference works just fine, yet using operators fails at runtime.

Exception in thread "main" java.lang.UnsupportedOperationException: This function has a reified type parameter and thus can only be inlined at compilation time, not called directly.
    at kotlin.jvm.internal.Intrinsics.throwUndefinedForReified(Intrinsics.java:173)
    at kotlin.jvm.internal.Intrinsics.throwUndefinedForReified(Intrinsics.java:167)
    at kotlin.jvm.internal.Intrinsics.reifyJavaClass(Intrinsics.java:201)

The code is as follows:

operator inline fun <reified T> get(address: Long): T {
    ...
}

operator inline fun <reified T> get(address: Int): T = get(address.toLong())

operator inline fun <reified T> set(address: Long, data: T) {
   ...
}

operator inline fun <reified T> set(address: Int, data: T): Unit = set(address.toLong(), data)

The interesting part is that I can do this with infix functions just fine, for example:

class Example { infix inline fun <reified T> foo(bar: Int) = Any() as T }

fun main(args: Array<String>) {
    val example = Example()
    val foobar: Any = example foo 12345
}

I can also do this with other operators, for example both of these work:

operator inline fun <reified T> minus(bar: Int) = foo<T>(bar)

operator inline fun <reified T> plus(bar: Int) = foo<T>(bar)

I also noticed that even invoke works correctly! This is strange since it seems both invoke and get would have identical implementations.

operator inline fun <reified T> invoke(bar: Int) = foo<T>(bar)

But if I add the following function to example: operator inline fun <reified T> get(bar: Int) = foo<T>(bar) and then try the following call I run into the error: val get: Any = example[12345]


Solution

  • It's a bug: https://youtrack.jetbrains.com/issue/KT-9211

    As a workaround, use .get(...) instead of [...]