Kotlin 1.3.11 has broken null-safety?

It's a bug caused by introducing contracts for the standard functions let, run, apply, also in Kotlin 1.3.

The fix is targeted to the version 1.3.20. See KT-28061 for details.


It looks like the Kotlin compiler is adding in a null return in case let doesn't execute. This is probably a bug, since it shouldn't compile, and doesn't in previous versions of Kotlin.

If we just compile your example, we get this:

@NotNull
public final String handle() {
    return null;
}

I think that's just a compiler optimization, since null?.let() will never execute.

Using an actual variable yields:

@NotNull
public final String handle() {
    return someNullableVariable != null ? "Ololo" : null;
}

In other words, let() doesn't execute if its reference is null. However, since this function needs to return something, the compiler just tells it to return null, since there's nothing else it could return.

Since the function is marked @NotNull, Kotlin will perform a null-check on anything referencing the function:

fun someOtherMethod() {
    handle().trim()
}

Becomes

public final void someOtherMethod() {
    String handle = handle();

    if (handle != null) {
        StringsKt__StringsKt.trim(handle).toString();
        return;
    }

    throw new Exception("null cannot be cast to non-null type kotlin.CharSequence");
}

There are two ways to handle this. You could change the return type on handle() to String?:

fun handle(): String? {
    someNullableVariable?.let { return "Ololo" }
}

Or you could return something else in case the variable is null:

fun handle(): String {
    someNullableVariable?.let { return "Ololo" }
    return "someNullableVariable was null"
}

It has to be a bug, because:

  • a return statement (or better: expression) is missing, since the lambda passed to let won't be invoked
  • a function with String as return type should never return null.

Interestingly, in Kotlin 1.2.x this does not even compile:

fun handle() : String {
    null?.let { return "Ololo"}
} 

Error:(6, 0) A 'return' expression required in a function with a block body ('{...}')

In Kotlin 1.3.11 it does.

In any case:

let won't be invoked, because the safe-call operator ? evaluates to null (in this case).

Tags:

Kotlin