FIR CFG: join/unify data flow from postponed lambdas at each level

For example:

    foo(
        // `if` joins A & B
        if (condition)
            run { ... } // A
        else
            run { ... }, // B
        run { ... } // C
    ) // `foo` unifies `A & B` and `C`, so if it is not resolved itself,
      // further `if`s, `when`s, safe calls outside it, etc. continue
      // building the correct type predicate until the next completed
      // call.

^KT-44512 Fixed
This commit is contained in:
pyos
2022-06-13 14:17:34 +02:00
committed by teamcity
parent 755c54553a
commit 63b0708ed5
17 changed files with 720 additions and 623 deletions
@@ -228,17 +228,25 @@ class PostponedLambdaEnterNode(owner: ControlFlowGraph, override val fir: FirAno
return visitor.visitPostponedLambdaEnterNode(this, data)
}
}
class PostponedLambdaExitNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNode<FirAnonymousFunctionExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitPostponedLambdaExitNode(this, data)
}
}
class UnionFunctionCallArgumentsNode(owner: ControlFlowGraph, override val fir: FirElement, level: Int, id: Int) : CFGNode<FirElement>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitUnionFunctionCallArgumentsNode(this, data)
}
}
class MergePostponedLambdaExitsNode(owner: ControlFlowGraph, override val fir: FirElement, level: Int, id: Int) : CFGNode<FirElement>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitMergePostponedLambdaExitsNode(this, data)
}
}
class AnonymousFunctionExpressionExitNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNode<FirAnonymousFunctionExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitAnonymousFunctionExpressionExitNode(this, data)
@@ -107,6 +107,7 @@ fun CFGNode<*>.render(): String =
is AnonymousFunctionExpressionExitNode -> "Exit anonymous function expression"
is UnionFunctionCallArgumentsNode -> "Call arguments union"
is MergePostponedLambdaExitsNode -> "Merge postponed lambda exits"
is ClassEnterNode -> "Enter class ${owner.name}"
is ClassExitNode -> "Exit class ${owner.name}"
@@ -46,6 +46,10 @@ abstract class ControlFlowGraphVisitor<out R, in D> {
return visitNode(node, data)
}
open fun visitMergePostponedLambdaExitsNode(node: MergePostponedLambdaExitsNode, data: D): R {
return visitNode(node, data)
}
open fun visitAnonymousFunctionExpressionExitNode(node: AnonymousFunctionExpressionExitNode, data: D): R {
return visitNode(node, data)
}
@@ -32,6 +32,10 @@ abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor<Unit, Nothi
visitNode(node)
}
open fun visitMergePostponedLambdaExitsNode(node: MergePostponedLambdaExitsNode) {
visitNode(node)
}
// ----------------------------------- Anonymous object -----------------------------------
open fun visitAnonymousObjectExitNode(node: AnonymousObjectExitNode) {
@@ -325,6 +329,10 @@ abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor<Unit, Nothi
visitUnionFunctionCallArgumentsNode(node)
}
final override fun visitMergePostponedLambdaExitsNode(node: MergePostponedLambdaExitsNode, data: Nothing?) {
visitMergePostponedLambdaExitsNode(node)
}
// ----------------------------------- Anonymous object -----------------------------------
final override fun visitAnonymousObjectExitNode(node: AnonymousObjectExitNode, data: Nothing?) {