Kotlin type erasure - why are functions differing only in generic type compilable while those only differing in return type are not?

Viewed 452

While working on the answer of How does erasure work in Kotlin? I found out some things I did not yet understand, nor did I find any sources why it is that way.

Why is the following not compilable?

fun bar(foo: List<*>) = ""
fun bar(foo: List<*>) = 2

while the following is?

fun bar(foo: List<String>) = ""
fun bar(foo: List<Int>) = 2

For me it even gets more curious, when adding a generic type that isn't even used, i.e. the following compiles too:

fun bar(foo: List<*>) = ""
fun <T> bar(foo: List<*>) = 2 // T isn't even used

As the last one doesn't even use T and as we know, generics are erased at runtime, why does this one work, while the variant without generic type does not?

Within the byte code methods only differing in return type are allowed (already described in the above linked answer).

Any hints, sources and/or references are welcome.

Added this question now also at discuss.kotlinlang.org.

1 Answers

The reason why these functions compile or don't compile is related to Kotlin's overload resolution rules. Kotlin does not use the expected type for resolving overloads, so when you call this function:

 val x = bar(listOf(""))

...there is no way for the Kotlin compiler to determine the type, and it does not allow you to disambiguate the call by specifying the type of x explicitly.

In the second case, there is no overload resolution problem because the functions have distinct parameter types, and there is no JVM name conflict problem because the functions have different return types (and thus different erased signatures). Therefore, the code compiles.

Related