FIR: assume a lambda returns Unit if it ends with a non-expression

While it is theoretically useful to know that `{ while(true) {} }`
returns Nothing, CFG node deadness is not precise enough to do that: if
the entire lambda is dead, it's no longer possible to find out whether
the loop is terminating. Besides, `while (true)` and `if (true)` are
pretty much the only constructs like that anyway.

Note that this commit does not affect resolution for lambdas that end in
a Nothing-returning expression, e.g. `throw`.
This commit is contained in:
pyos
2022-12-09 22:11:44 +01:00
committed by Dmitriy Novozhilov
parent 803abfeba8
commit 1eccb9aea1
12 changed files with 47 additions and 42 deletions
@@ -13,6 +13,9 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNothingTypeRef
import org.jetbrains.kotlin.fir.types.isNothing
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.utils.SmartList
@@ -891,17 +894,18 @@ class AnnotationExitNode(owner: ControlFlowGraph, override val fir: FirAnnotatio
// ----------------------------------- Stub -----------------------------------
object FirStub : FirElement {
object FirStub : FirExpression() {
override val source: KtSourceElement? get() = null
override val typeRef: FirTypeRef = FirImplicitNothingTypeRef(null)
override val annotations: List<FirAnnotation> get() = listOf()
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
return this
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirExpression = this
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement = this
override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) { assert(newAnnotations.isEmpty()) }
override fun replaceTypeRef(newTypeRef: FirTypeRef) { assert(newTypeRef.isNothing) }
}
// ----------------------------------- Smart-cast node -----------------------------------
class SmartCastExpressionExitNode(owner: ControlFlowGraph, override val fir: FirSmartCastExpression, level: Int, id: Int) : CFGNode<FirSmartCastExpression>(owner, level, id) {