b42a7be0de
After we added "careful approximation of contravariant projections" in584b70719e, some SAM conversions started to require an additional implicit cast of the functional value before it is converted to the SAM interface. The target type of this implicit cast was computed incorrectly because it didn't contain nullability of the SAM type. This could lead to a situation where a nullable value was incorrectly cast to a non-null type, which caused a missing null check and NPE at runtime. For example, let's consider the test `kt54600.kt`. SAM conversion happens in the constructor call `J(filter)`. Before584b70719e, the IR for that argument was (irrelevant things are omitted for simplicity): TYPE_OP SAM_CONVERSION type=Condition<String!>! GET_VAR filter type=Function1<String, Boolean>? After584b70719e, the IR became: TYPE_OP SAM_CONVERSION type=Condition<Any?>! TYPE_OP IMPLICIT_CAST type=Function1<Any?, Boolean> GET_VAR filter type=Function1<String, Boolean>? Note the two changes: * The resulting SAM type changed from `Condition<String!>` to `Condition<Any?>`. This is exactly the point of the "careful approximation" change, because just erasing the "in" projection from the parameter type is incorrect, see the explanation for that change. * The value is now implicitly cast to the _non-null_ function type before it is SAM-converted. The presence of the cast is fine, but the fact that it's to a non-null type is an oversight. The target type for this cast is computed at `KotlinType.getSubstitutedFunctionTypeForSamType` in psi2ir. Now it extracts the nullability from the SAM type and retains it in the resulting function type. After this change, the IR for the argument becomes: TYPE_OP SAM_CONVERSION type=Condition<Any?>! TYPE_OP IMPLICIT_CAST type=Function1<Any?, Boolean>! GET_VAR filter type=Function1<String, Boolean>? Note that the target type is now flexible, as the resulting SAM type. Another option would be to make it nullable, as the type of the functional value, but there doesn't seem to be any difference. #KT-54600 Fixed
28 lines
414 B
Kotlin
Vendored
28 lines
414 B
Kotlin
Vendored
// TARGET_BACKEND: JVM
|
|
// DUMP_IR
|
|
// FILE: box.kt
|
|
|
|
fun box(): String =
|
|
foo(null)
|
|
|
|
fun foo(filter: ((String) -> Boolean)?): String {
|
|
J(filter)
|
|
return "OK"
|
|
}
|
|
|
|
// FILE: J.java
|
|
|
|
public class J {
|
|
public J(Condition<? super String> filter) {
|
|
if (filter != null) {
|
|
filter.value("");
|
|
}
|
|
}
|
|
}
|
|
|
|
// FILE: Condition.java
|
|
|
|
public interface Condition<T> {
|
|
boolean value(T t);
|
|
}
|