Cannot use the invoke operator after a non-null check

Here is a class similar to one I have:

class Test(
    private val testInvokeOperator: (() -> Unit)? = null
) {
    fun test() {
        if (testInvokeOperator != null) {
            testInvokeOperator()
        }
    }
}

I expect to be able to use the invoke operator on the lambda since it’s smart-casted to a non-nullable type, but the compiler gives me an error saying “Only safe and non-null asserted calls are allowed…” (the one you get when trying to call a method on a null reference).

If I add a non-null assertion (!!) I get a warning that the assertion is unnecessary.

Everything works as expected if I replace the operator with the invoke method call (no need to perform a null-safe call).

I use:
Kotlin 1.3.72
Android Studio 3.6.3
AGP 3.5.3

Since the testInvokeOperator reference is immutable (val), I consider this a compiler bug. However you can work around it with a local copy:

class Test(
    private val testInvokeOperator: (() -> Unit)? = null
) {
    fun test() {
        val operatorCopy = testInvokeOperator
        if (operatorCopy != null) {
            operatorCopy()
        }
    }
}

Thanks for the suggestion! Personally I prefer using .invoke() since it’s much easier to refactor such places once the bug is fixed - you just need to delete the .invoke part.

I just found the related issue https://youtrack.jetbrains.com/issue/KT-4113

2 Likes

One more option (to reduce variable scope, final bytecode will be the same):

class Test(
    private val testInvokeOperator: (() -> Unit)? = null
) {
    fun test() {
        testInvokeOperator?.let {
             it()
        }
    }
}