How does the Kotlin null-check compiler contract work?

295 Views Asked by At

I have a couple of custom scope functions that all look similar to this one:

@OptIn(ExperimentalContracts::class)
inline fun <R> R.applyIf(condition: Boolean, block: R.() -> Unit): R {
  contract {
    callsInPlace(block, InvocationKind.EXACTLY_ONCE)
  }

  if(condition) block()
  return this
}

It has the same effect as apply(...) but the block only gets executed if the condition is met. The function works wonderfully but there is one caveat. If the condition contains null-checks for example, those not-null guarantees do not translate into the block that gets executed.

So for example:

.applyIf(source != null) {
  sourceClassName = source.className
  sourceMethodName = source.methodName
})

The above results in a compiler warning because I am using source without the ?: and !! operators. The IntelliJ tooltip says

Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type LogSource? (the source variable is of type LogSource)

What would be the best way to get the same behavior as this case:

if(source != null) { 
  [...].apply {
    sourceClassName = source.className
    sourceMethodName = source.methodName
  }
}

I suppose using a predicate or a provider instead of a boolean would be the first step, but what is the correct contract syntax to syntactically say "if the condition contains null-checks, the confirmed non-null values are valid in and throughout the block unless changed"?

0

There are 0 best solutions below