Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

throw statement in Kotlin

in Kotlin expressions like

fun main() {
    throw throw throw RuntimeException("boom")
}

or

fun main() {
    throw throw return
}

are syntactically correct

I understand ideas behind it, but I wonder why there is no Warn (at least in Itellij) when writing such nonsense.

like image 249
sayhello Avatar asked Feb 27 '26 13:02

sayhello


1 Answers

This is reported as a minor problem in KT-22621 "throw throw Exception()": False negative UNREACHABLE_CODE warning. It should be noted that unreachable code is warned if you put parentheses:

throw (throw Exception())
// or
throw (return)

Also, return throws Exception() gives the warning too.

Unfortunately, it is still an open issue after 4 years.

After reading Kotlin's source code for a bit, I think this is unintentional. Let's consider ControlFlowProcessor.kt, visitThrowExpression:

override fun visitThrowExpression(expression: KtThrowExpression) {
    mark(expression)

    generateJumpsToCatchAndFinally()

    val thrownExpression = expression.thrownExpression ?: return
    generateInstructions(thrownExpression)

    val thrownValue = builder.getBoundValue(thrownExpression) ?: return
    builder.throwException(expression, thrownValue)
}

Consider throw throw Exception(). When the first throw is visited, generateInstructions(thrownExpression) generates the part of the CFG that corresponds to throw Exception(). This causes the second throw to be visited, generating the correct CFG for throw Exception().

The problem comes, when builder.getValue(thrownExpression) gets called. This gets a PseudoValue from the CFG builder that represents the thrown value. However, (I suspect that) this returns nil and builder.throwException is not called. This is because when building the CFG for throw Exception(), no value is bound. Compare this to what happens in visitParenthesizedExpression, or visitCallExpression, but you'd need to trace deeper.

This doesn't affect control flow analysis too much, since the part of the CFG generated for throw Exception() is correct. The CFG does end up missing a node to represent the outer throw though, which is what builder.throwException would have added. This node would have been marked as unreachable and a warning been issued, but this node doesn't even exist, so no warnings.

like image 98
Sweeper Avatar answered Mar 02 '26 05:03

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!