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 returnnull
.
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).