Why is unused Kotlin function failing at load time?

Viewed 48

If I include the following Kotlin function in any Kotlin file, it will cause a failure to load that file. I'd like to understand why.

fun optionalUnitReturningOptionalNothing(): Unit? {
    fun localOptionalNothing(): Nothing? {
        return null
    }
    return localOptionalNothing()
}

Here is a sample error message:

Error: Unable to initialize main class NullAssignTestKt
Caused by: java.lang.VerifyError: Bad return type
Exception Details:
  Location:
    NullAssignTestKt.optionalUnitReturningOptionalNothing()Lkotlin/Unit; @3: areturn
  Reason:
    Type 'java/lang/Void' (current frame, stack[0]) is not assignable to 'kotlin/Unit' (from method signature)
  Current Frame:
    bci: @3
    flags: { }
    locals: { }
    stack: { 'java/lang/Void' }
  Bytecode:
    0000000: b800 0bb0                              

Moving the internal function outside does not fix the problem, however, the following compiles, loads and executes without a problem:

fun optionalNothing(): Nothing? { return null }
fun optionalUnit(): Unit? { return null }
val lambdaOptionalUnitReturningOptionalNothing: () -> Unit? = { optionalNothing() }

fun main() {
    optionalNothing() ?: println("optional nothing worked")
    optionalUnit() ?: println("optional unit worked")
    lambdaOptionalUnitReturningOptionalNothing() ?: println("lambda worked")
}
1 Answers

The first version doesn't work because you're trying to return Nothing? from a function whose return type is Unit. Kotlin isn't detecting the problem at compile-time, but it is detecting it at runtime.

The second version works because you're not actually returning the value of the inner function call. optionalNothing() runs, and then optionalUnit() returns Unit.

    private fun optionalNothing(): Nothing? { return null }
    private fun optionalUnit(): Unit? { return null }

    /**
     * This wont load because you can't actually return Nothing?.
     */
    fun optionalUnitReturningOptionalNothing(): Unit? {
        fun localOptionalNothing(): Nothing? {
            return null
        }
        return localOptionalNothing() 
    }

    /**
     * This is fine because it returns Unit.
     * optionalNothing gets called, but it has no return value.
     */
    private val lambdaOptionalUnitReturningOptionalNothing1: () -> Unit? = { optionalNothing() }

    /**
     * This wont even compile.
     */
    private val lambdaOptionalUnitReturningOptionalNothing2: () -> Unit? = { return optionalNothing() }

    /**
     * Neither will this.
     */
    private val lambdaOptionalUnitReturningOptionalNothing3: () -> Unit? = optionalNothing()
Related