From 86683e94fc0a2b6e8537a0443f0c1cba2f3a8b82 Mon Sep 17 00:00:00 2001 From: "simon.ogorodnik" Date: Wed, 13 May 2020 16:43:43 +0300 Subject: [PATCH] [FIR] Fix cfg crash with multiple postponed arguments --- .../resolveWithStdlib/complexPostponedCfg.dot | 115 ++++++++++++++++++ .../resolveWithStdlib/complexPostponedCfg.kt | 20 +++ .../resolveWithStdlib/complexPostponedCfg.txt | 20 +++ ...FirDiagnosticsWithStdlibTestGenerated.java | 5 + .../dfa/cfg/ControlFlowGraphBuilder.kt | 3 +- 5 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot new file mode 100644 index 00000000000..a631ade1f72 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot @@ -0,0 +1,115 @@ +digraph complexPostponedCfg_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter class FirBase" style="filled" fillcolor=red]; + 1 [label="Exit class FirBase" style="filled" fillcolor=red]; + } + 0 -> {1} [color=green]; + + subgraph cluster_1 { + color=red + 2 [label="Enter class FirFunctionCall" style="filled" fillcolor=red]; + 3 [label="Exit class FirFunctionCall" style="filled" fillcolor=red]; + } + 2 -> {3} [color=green]; + + subgraph cluster_2 { + color=red + 4 [label="Enter function foo" style="filled" fillcolor=red]; + 6 [label="Access variable R|/statements|"]; + 7 [label="Function call: R|/statements|.R|kotlin/collections/last|()"]; + 8 [label="Type operator: (R|/statements|.R|kotlin/collections/last|() as R|FirFunctionCall|)"]; + 9 [label="Postponed enter to lambda"]; + subgraph cluster_3 { + color=blue + 19 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 21 [label="Postponed enter to lambda"]; + subgraph cluster_4 { + color=blue + 24 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 26 [label="Access variable this@R|special/anonymous|"]; + 27 [label="Function call: this@R|special/anonymous|.R|FakeOverride|(...)"]; + 28 [label="Access variable R|/arguments|"]; + 29 [label="Function call: R|/arguments|.R|kotlin/collections/last|()"]; + 30 [label="Type operator: (R|/arguments|.R|kotlin/collections/last|() as R|FirFunctionCall|)"]; + 31 [label="Postponed enter to lambda"]; + subgraph cluster_5 { + color=blue + 35 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 37 [label="Access variable this@R|special/anonymous|"]; + 38 [label="Function call: this@R|special/anonymous|.R|FakeOverride|(...)"]; + 39 [label="Access variable R|/explicitReceiver|"]; + 40 [label="Type operator: (R|/explicitReceiver| as R|FirFunctionCall|)"]; + 41 [label="Function call: this@R|special/anonymous|.R|FakeOverride|(...)"]; + 36 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 34 [label="Call arguments union" style="filled" fillcolor=yellow]; + 32 [label="Postponed exit from lambda"]; + 33 [label="Function call: R|kotlin/with|(...)"]; + 25 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 22 [label="Postponed exit from lambda"]; + 23 [label="Function call: R|kotlin/collections/buildList|(...)"]; + 20 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 12 [label="Call arguments union" style="filled" fillcolor=yellow]; + 10 [label="Postponed exit from lambda"]; + 11 [label="Function call: R|kotlin/with|(...)"]; + 13 [label="Stub" style="filled" fillcolor=gray]; + 14 [label="Variable declaration: lval firstCalls: R|kotlin/Nothing|" style="filled" fillcolor=gray]; + 15 [label="Access variable R|/firstCalls|" style="filled" fillcolor=gray]; + 16 [label="Stub" style="filled" fillcolor=gray]; + 17 [label="Jump: ^foo R|/firstCalls|" style="filled" fillcolor=gray]; + 18 [label="Stub" style="filled" fillcolor=gray]; + 5 [label="Exit function foo" style="filled" fillcolor=red]; + } + 4 -> {6}; + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {19}; + 9 -> {10} [color=red]; + 10 -> {11} [color=green]; + 11 -> {5}; + 11 -> {13} [style=dotted]; + 12 -> {11}; + 13 -> {14} [style=dotted]; + 14 -> {15} [style=dotted]; + 15 -> {5 16} [style=dotted]; + 16 -> {17} [style=dotted]; + 17 -> {5 18} [style=dotted]; + 18 -> {5} [style=dotted]; + 19 -> {21}; + 20 -> {10} [color=green]; + 20 -> {12} [color=red]; + 21 -> {24}; + 21 -> {22} [color=red]; + 22 -> {23}; + 23 -> {20}; + 24 -> {26}; + 25 -> {22} [color=green]; + 25 -> {12} [color=red]; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31}; + 31 -> {35}; + 31 -> {32} [color=red]; + 32 -> {33} [color=green]; + 33 -> {25}; + 34 -> {33} [color=red]; + 35 -> {37}; + 36 -> {32} [color=green]; + 36 -> {34} [color=red]; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {36}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.kt new file mode 100644 index 00000000000..995b779c47d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.kt @@ -0,0 +1,20 @@ +// !DUMP_CFG + +interface FirBase +interface FirFunctionCall : FirBase + + +fun foo(statements: List, arguments: List, explicitReceiver: FirBase): List { + + val firstCalls = with(statements.last() as FirFunctionCall) setCall@{ + buildList { + add(this@setCall) + with(arguments.last() as FirFunctionCall) plusCall@{ + add(this@plusCall) + add(explicitReceiver as FirFunctionCall) + } + } + } + + return firstCalls +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt new file mode 100644 index 00000000000..00a042f9925 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt @@ -0,0 +1,20 @@ +FILE: complexPostponedCfg.kt + public abstract interface FirBase : R|kotlin/Any| { + } + public abstract interface FirFunctionCall : R|FirBase| { + } + public final fun foo(statements: R|kotlin/collections/List|, arguments: R|kotlin/collections/List|, explicitReceiver: R|FirBase|): R|kotlin/collections/List| { + lval firstCalls: R|kotlin/Nothing| = R|kotlin/with|((R|/statements|.R|kotlin/collections/last|() as R|FirFunctionCall|), = setCall@fun R|FirFunctionCall|.(): R|kotlin/Nothing| { + ^ R|kotlin/collections/buildList|( = buildList@fun R|kotlin/collections/MutableList|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|FakeOverride|(this@R|special/anonymous|) + ^ R|kotlin/with|((R|/arguments|.R|kotlin/collections/last|() as R|FirFunctionCall|), = plusCall@fun R|FirFunctionCall|.(): R|kotlin/Boolean| { + this@R|special/anonymous|.R|FakeOverride|(this@R|special/anonymous|) + ^ this@R|special/anonymous|.R|FakeOverride|((R|/explicitReceiver| as R|FirFunctionCall|)) + } + ) + } + ) + } + ) + ^foo R|/firstCalls| + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 33b4f17a1ac..2b624bbd943 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -68,6 +68,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/companionLoad.kt"); } + @TestMetadata("complexPostponedCfg.kt") + public void testComplexPostponedCfg() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.kt"); + } + @TestMetadata("components.kt") public void testComponents() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/components.kt"); 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 32bd4ace9c5..1518a0e858a 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 @@ -758,11 +758,12 @@ class ControlFlowGraphBuilder { var hasPostponedLambdas = false val iterator = exitsFromCompletedPostponedAnonymousFunctions.iterator() + val lastPostponedLambdaExitNode = lastNode while (iterator.hasNext()) { val exitNode = iterator.next() if (node.level >= exitNode.level) continue hasPostponedLambdas = true - if (exitNode == lastNode) { + if (exitNode == lastPostponedLambdaExitNode) { addEdge(lastNodes.pop(), node, preferredKind = EdgeKind.Cfg) kind = EdgeKind.Dfg hasDirectPreviousNode = true