Kotlin contract infer return value instead of argument value

559 Views Asked by At

I have a function that looks something like:

fun MyInput?.toOutput() : Output? {
  if (this == null) return null
  return Output(this.someValue)
}

In places where I know that my MyInput is non-null (for example, inside a method that takes a input: MyInput as an arg), I'd like to be able to use input.toOutput as Output instead of Output?

I've tried using

contract {
  returnsNotNull() implies (this@toOutput != null)
}

But that has the implication backwards. That tells me that if toOutput returns a non-null type, that my input was non-null. I want to tell the analyzer things about the return value based on the arguments. In Java, I could use org.jetbrains.annotations.@Contract("null -> null ; !null -> !null") to accomplish this.

Is there a way to do this in Kotlin?

1

There are 1 best solutions below

0
On BEST ANSWER

You don't need contracts for this. You just need to make a non-nullable overload. Like this:

fun MyInput?.toOutput(): Output? {
  if (this == null) return null
  return Output(this.someValue)
}

fun MyInput.toOutput(): Output = Output(this.someValue)

However, this will not work out of the box on the JVM, because the function signatures will clash. To make it work, you have to give one of the functions a new name with the @JvmName annotation. For example:

@JvmName("toOutputNonNull")
fun MyInput.toOutput(): Output = Output(this.someValue)

You will still be able to call it like input.toOutput() from Kotlin, but it will become something like FileNameKt.toOutputNonNull(input) if you call it from Java.