Files
kotlin-fork/compiler/testData/codegen/box/sam/kt54600.kt
T
Alexander Udalov b42a7be0de Psi2ir: keep nullability when substituting function type for SAM type
After we added "careful approximation of contravariant projections" in
584b70719e, 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)`. Before 584b70719e, 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>?

After 584b70719e, 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
2022-10-25 11:20:23 +00:00

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);
}