From bcc54deb6448c4a4419c301a2b8b28e0ed4552c5 Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 28 Nov 2022 17:33:24 +0100 Subject: [PATCH] FIR CFA: fix deadness of various nodes * `do { continue } while (x)`: block exit is dead, condition is not; * `try { a?.incomplete() } catch (e) { x }`: when the call is completed and found to return `Nothing`, the safe call exit node is still live because `a` could still be null; * `f(a@{ g { return@a } }, x)`: if call to `g` is not completed, there should not be a dead data flow edge from the lambda to `f` because there's no such thing as a dead data flow edge (DeadForward is CF+DF). --- .../resolve/dfa/cfg/ControlFlowGraphBuilder.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index 3285061e404..e0203c68e2a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.buildUnitExpression -import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.dfa.* import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType @@ -21,7 +20,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.util.ListMultimap import org.jetbrains.kotlin.fir.util.listMultimapOf -import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.utils.addToStdlib.runIf import kotlin.random.Random @@ -342,9 +340,13 @@ class ControlFlowGraphBuilder { } } else { for ((exit, kind) in currentLevelExits) { - // Since `node` is a union node, it is dead iff any input is dead. For once, `propagateDeadness` - // semantics are correct without an `updateDeadStatus`. - addEdge(exit, node, preferredKind = kind, propagateDeadness = kind.usedInCfa) + // Do not add data flow edges from non-terminating lambdas; there is no "dead data flow only" + // `EdgeKind`. TODO? + if (kind.usedInCfa || !exit.isDead) { + // Since `node` is a union node, it is dead iff any input is dead. For once, `propagateDeadness` + // semantics are correct without an `updateDeadStatus`. + addEdge(exit, node, preferredKind = kind) + } } } } @@ -854,6 +856,8 @@ class ControlFlowGraphBuilder { // This may sound shocking, but `do...while` conditions can `continue` to themselves, // so we can't pop the node off the stack here. val conditionEnterNode = loopConditionEnterNodes.top().also { addNewSimpleNode(it) } + // Might have had live `continue`s with an unreachable block exit, so recompute deadness. + conditionEnterNode.updateDeadStatus() levelCounter++ return blockExitNode to conditionEnterNode } @@ -1103,7 +1107,8 @@ class ControlFlowGraphBuilder { CFGNode.addEdge(node, stub, EdgeKind.DeadForward, propagateDeadness = false) for ((to, edge) in edges) { val kind = if (edge.kind.isBack) EdgeKind.DeadBackward else EdgeKind.DeadForward - CFGNode.addEdge(stub, to, kind, propagateDeadness = true, label = edge.label) + CFGNode.addEdge(stub, to, kind, propagateDeadness = false, label = edge.label) + to.updateDeadStatus() propagateDeadnessForward(to) } }