Type Parameter inference results in NullPointerException?


The following code tells everything:

class A<E>(val a: E) {
    fun <T> get(s: T?) = a as T

    fun get(): E = get(null) //Compiles OK, but throw NullPointerException when running.

    fun get2(): E = get<E>(null) //Compiles OK and no exceptions.

fun main(args: Array<String>) {
    val a = A(1)

running result is

Exception in thread "main" java.lang.NullPointerException
	at A.get(Bug.kt:13)
	at A.main(Bug.kt:21)


Using Kotlin Bytecode to decompile the code, we get:

public final Object get() {
      throw null;// Why?

public final Object get2() {
      return this.get((Object)null);

Which shows that NullPointerException is determined at compilation and no warning about this.Only runtime NullPointerException is thrown.


T is different for get() and get2(): Nothing and Int respectively. So that explains why the behavior is different. You can see the inferred type in IntelliJ IDEA if you use this code:

val getBody = a.get(null) // Inferred type is Nothing
val get2Body = a.get<Int>(null) // Inferred type is Int

The fact that the resulting exception of get() is a NullPointerException, seems a bug to me. If I add a function with Nothing as the explicit type to A, I get a ClassCastException when I call it:

fun getNothing(s: Nothing?): Nothing = a as Nothing


val getBody = a.get(null) // Results in NullPointerException
val getBodyNothing = a.get<Nothing>(null) // Results in NullPointerException
val explicitNothing = a.getNothing(null) // Results in ClassCastException: java.lang.Integer cannot be cast to java.lang.Void


No, it doesn’t. When calling get(T) without a type parameter, the compiler infers the common type of the type of a and the null that you pass to get(T): Nothing.


yeah. val doesn’t help type inference. so the type of a.get(null) is Nothing
If you change the code to val getBody:Int=a.get(null), then the type is Int


When giving the arguments, the compiler doesn’t infer the type from the returned type?


As far as I know it uses both the argument type and the return type, and selects the most specific common type of both types.