diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot index 198465fd462..9287b64249c 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot @@ -61,14 +61,14 @@ digraph inplaceLambdaInControlFlowExpressions_kt { 23 [label="Postponed enter to lambda"]; subgraph cluster_9 { color=blue - 33 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 32 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_10 { color=blue - 34 [label="Enter block"]; - 35 [label="Function call: R|/materialize|()"]; - 36 [label="Exit block"]; + 33 [label="Enter block"]; + 34 [label="Function call: R|/materialize|()"]; + 35 [label="Exit block"]; } - 37 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 36 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } 24 [label="Postponed exit from lambda"]; 25 [label="Function call: R|kotlin/run|(...)"]; @@ -77,11 +77,10 @@ digraph inplaceLambdaInControlFlowExpressions_kt { 27 [label="Exit when branch result"]; 28 [label="Exit when"]; } - 29 [label="Call arguments union" style="filled" fillcolor=yellow]; - 30 [label="Variable declaration: lval x: R|kotlin/String|"]; - 31 [label="Exit block"]; + 29 [label="Variable declaration: lval x: R|kotlin/String|"]; + 30 [label="Exit block"]; } - 32 [label="Exit function test_1" style="filled" fillcolor=red]; + 31 [label="Exit function test_1" style="filled" fillcolor=red]; } 8 -> {9}; 9 -> {10}; @@ -98,7 +97,7 @@ digraph inplaceLambdaInControlFlowExpressions_kt { 20 -> {28}; 21 -> {22}; 22 -> {23}; - 23 -> {33}; + 23 -> {32}; 23 -> {24} [color=red]; 24 -> {25}; 25 -> {26}; @@ -107,78 +106,77 @@ digraph inplaceLambdaInControlFlowExpressions_kt { 28 -> {29}; 29 -> {30}; 30 -> {31}; - 31 -> {32}; + 32 -> {33}; 33 -> {34}; 34 -> {35}; 35 -> {36}; - 36 -> {37}; - 37 -> {29} [color=red]; - 37 -> {24} [color=green]; + 36 -> {24} [color=green]; subgraph cluster_11 { color=red - 38 [label="Enter function test_2" style="filled" fillcolor=red]; + 37 [label="Enter function test_2" style="filled" fillcolor=red]; subgraph cluster_12 { color=blue - 39 [label="Enter block"]; + 38 [label="Enter block"]; subgraph cluster_13 { color=blue - 40 [label="Try expression enter"]; + 39 [label="Try expression enter"]; subgraph cluster_14 { color=blue - 41 [label="Try main block enter"]; + 40 [label="Try main block enter"]; subgraph cluster_15 { color=blue - 42 [label="Enter block"]; - 43 [label="Postponed enter to lambda"]; + 41 [label="Enter block"]; + 42 [label="Postponed enter to lambda"]; subgraph cluster_16 { color=blue - 58 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 57 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_17 { color=blue - 59 [label="Enter block"]; - 60 [label="Function call: R|/materialize|()"]; - 61 [label="Exit block"]; + 58 [label="Enter block"]; + 59 [label="Function call: R|/materialize|()"]; + 60 [label="Exit block"]; } - 62 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 61 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 44 [label="Postponed exit from lambda"]; - 45 [label="Function call: R|kotlin/run|(...)"]; - 46 [label="Exit block"]; + 43 [label="Postponed exit from lambda"]; + 44 [label="Function call: R|kotlin/run|(...)"]; + 45 [label="Exit block"]; } - 47 [label="Try main block exit"]; + 46 [label="Try main block exit"]; } subgraph cluster_18 { color=blue - 48 [label="Catch enter"]; + 47 [label="Catch enter"]; subgraph cluster_19 { color=blue - 49 [label="Enter block"]; - 50 [label="Const: String()"]; - 51 [label="Exit block"]; + 48 [label="Enter block"]; + 49 [label="Const: String()"]; + 50 [label="Exit block"]; } - 52 [label="Catch exit"]; + 51 [label="Catch exit"]; } - 53 [label="Try expression exit"]; + 52 [label="Try expression exit"]; } - 54 [label="Call arguments union" style="filled" fillcolor=yellow]; - 55 [label="Variable declaration: lval x: R|kotlin/String|"]; - 56 [label="Exit block"]; + 53 [label="Call arguments union" style="filled" fillcolor=yellow]; + 54 [label="Variable declaration: lval x: R|kotlin/String|"]; + 55 [label="Exit block"]; } - 57 [label="Exit function test_2" style="filled" fillcolor=red]; + 56 [label="Exit function test_2" style="filled" fillcolor=red]; } + 37 -> {38}; 38 -> {39}; 39 -> {40}; - 40 -> {41}; - 41 -> {57 48 42}; - 42 -> {43}; - 43 -> {58}; - 43 -> {44} [color=red]; + 40 -> {56 47 41}; + 41 -> {42}; + 42 -> {57}; + 42 -> {43} [color=red]; + 43 -> {44}; 44 -> {45}; 45 -> {46}; - 46 -> {47}; - 47 -> {53}; - 48 -> {57 49}; + 46 -> {52}; + 47 -> {56 48}; + 48 -> {49}; 49 -> {50}; 50 -> {51}; 51 -> {52}; @@ -186,56 +184,55 @@ digraph inplaceLambdaInControlFlowExpressions_kt { 53 -> {54}; 54 -> {55}; 55 -> {56}; - 56 -> {57}; + 57 -> {58}; 58 -> {59}; 59 -> {60}; 60 -> {61}; - 61 -> {62}; - 62 -> {54} [color=red]; - 62 -> {44} [color=green]; + 61 -> {53} [color=red]; + 61 -> {43} [color=green]; subgraph cluster_20 { color=red - 63 [label="Enter function test_3" style="filled" fillcolor=red]; + 62 [label="Enter function test_3" style="filled" fillcolor=red]; subgraph cluster_21 { color=blue - 64 [label="Enter block"]; - 65 [label="Postponed enter to lambda"]; + 63 [label="Enter block"]; + 64 [label="Postponed enter to lambda"]; subgraph cluster_22 { color=blue - 73 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 72 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_23 { color=blue - 74 [label="Enter block"]; - 75 [label="Function call: R|/materialize|()"]; - 76 [label="Exit block"]; + 73 [label="Enter block"]; + 74 [label="Function call: R|/materialize|()"]; + 75 [label="Exit block"]; } - 77 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 76 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 66 [label="Postponed exit from lambda"]; - 67 [label="Function call: R|kotlin/run|(...)"]; - 68 [label="Check not null: R|kotlin/run|(...)!!"]; - 69 [label="Call arguments union" style="filled" fillcolor=yellow]; - 70 [label="Variable declaration: lval x: R|kotlin/String|"]; - 71 [label="Exit block"]; + 65 [label="Postponed exit from lambda"]; + 66 [label="Function call: R|kotlin/run|(...)"]; + 67 [label="Check not null: R|kotlin/run|(...)!!"]; + 68 [label="Call arguments union" style="filled" fillcolor=yellow]; + 69 [label="Variable declaration: lval x: R|kotlin/String|"]; + 70 [label="Exit block"]; } - 72 [label="Exit function test_3" style="filled" fillcolor=red]; + 71 [label="Exit function test_3" style="filled" fillcolor=red]; } + 62 -> {63}; 63 -> {64}; - 64 -> {65}; - 65 -> {73}; - 65 -> {66} [color=red]; + 64 -> {72}; + 64 -> {65} [color=red]; + 65 -> {66}; 66 -> {67}; 67 -> {68}; 68 -> {69}; 69 -> {70}; 70 -> {71}; - 71 -> {72}; + 72 -> {73}; 73 -> {74}; 74 -> {75}; 75 -> {76}; - 76 -> {77}; - 77 -> {69} [color=red]; - 77 -> {66} [color=green]; + 76 -> {68} [color=red]; + 76 -> {65} [color=green]; } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot new file mode 100644 index 00000000000..2c254d2fc95 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot @@ -0,0 +1,250 @@ +digraph lambdaInWhenBranch_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter class Sealed" style="filled" fillcolor=red]; + 1 [label="Exit class Sealed" style="filled" fillcolor=red]; + } + 0 -> {1} [color=green]; + + subgraph cluster_1 { + color=red + 2 [label="Enter function " style="filled" fillcolor=red]; + 3 [label="Delegated constructor call: super()"]; + 4 [label="Exit function " style="filled" fillcolor=red]; + } + 2 -> {3}; + 3 -> {4}; + + subgraph cluster_2 { + color=red + 5 [label="Enter class SubClass1" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 7 [label="Enter property" style="filled" fillcolor=red]; + 8 [label="Access variable R|/t|"]; + 9 [label="Exit property" style="filled" fillcolor=red]; + } + 6 [label="Exit class SubClass1" style="filled" fillcolor=red]; + } + 5 -> {7} [color=green]; + 7 -> {8}; + 8 -> {9}; + 9 -> {6} [color=green]; + + subgraph cluster_4 { + color=red + 10 [label="Enter function " style="filled" fillcolor=red]; + 11 [label="Delegated constructor call: super()"]; + 12 [label="Exit function " style="filled" fillcolor=red]; + } + 10 -> {11}; + 11 -> {12}; + + subgraph cluster_5 { + color=red + 13 [label="Enter function getter" style="filled" fillcolor=red]; + 14 [label="Exit function getter" style="filled" fillcolor=red]; + } + 13 -> {14}; + + subgraph cluster_6 { + color=red + 15 [label="Enter function component1" style="filled" fillcolor=red]; + 16 [label="Exit function component1" style="filled" fillcolor=red]; + } + 15 -> {16}; + + subgraph cluster_7 { + color=red + 17 [label="Enter function copy" style="filled" fillcolor=red]; + subgraph cluster_8 { + color=blue + 19 [label="Enter default value of t" style="filled" fillcolor=red]; + 20 [label="Access variable R|/SubClass1.t|"]; + 21 [label="Exit default value of t" style="filled" fillcolor=red]; + } + 18 [label="Exit function copy" style="filled" fillcolor=red]; + } + 17 -> {19 18}; + 19 -> {20}; + 20 -> {21}; + + subgraph cluster_9 { + color=red + 22 [label="Enter class SubClass2" style="filled" fillcolor=red]; + 23 [label="Exit class SubClass2" style="filled" fillcolor=red]; + } + 22 -> {23} [color=green]; + + subgraph cluster_10 { + color=red + 24 [label="Enter function " style="filled" fillcolor=red]; + 25 [label="Delegated constructor call: super()"]; + 26 [label="Exit function " style="filled" fillcolor=red]; + } + 24 -> {25}; + 25 -> {26}; + + subgraph cluster_11 { + color=red + 27 [label="Enter function copy" style="filled" fillcolor=red]; + 28 [label="Exit function copy" style="filled" fillcolor=red]; + } + 27 -> {28}; + + subgraph cluster_12 { + color=red + 29 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_13 { + color=blue + 30 [label="Enter block"]; + subgraph cluster_14 { + color=blue + 31 [label="Enter when"]; + 32 [label="Access variable R|/p|"]; + subgraph cluster_15 { + color=blue + 33 [label="Enter when branch condition "]; + 34 [label="Type operator: ($subj$ is R|SubClass1|)"]; + 35 [label="Exit when branch condition"]; + } + subgraph cluster_16 { + color=blue + 36 [label="Enter when branch condition "]; + 37 [label="Type operator: ($subj$ is R|SubClass2|)"]; + 38 [label="Exit when branch condition"]; + } + 39 [label="Enter when branch result"]; + subgraph cluster_17 { + color=blue + 40 [label="Enter block"]; + 41 [label="Const: String()"]; + 42 [label="Exit block"]; + } + 43 [label="Exit when branch result"]; + 44 [label="Enter when branch result"]; + subgraph cluster_18 { + color=blue + 45 [label="Enter block"]; + 46 [label="Const: String()"]; + 47 [label="Postponed enter to lambda"]; + subgraph cluster_19 { + color=blue + 78 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_20 { + color=blue + 79 [label="Enter block"]; + 80 [label="Access variable R|/it|"]; + 81 [label="Exit block"]; + } + 82 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 48 [label="Postponed exit from lambda"]; + 49 [label="Function call: String().R|kotlin/let|(...)"]; + 50 [label="Exit block"]; + } + 51 [label="Exit when branch result"]; + 52 [label="Exit when"]; + } + 53 [label="Access variable R|/p|"]; + 54 [label="Access variable #"]; + subgraph cluster_21 { + color=blue + 55 [label="Enter when"]; + 56 [label="Access variable R|/p|"]; + subgraph cluster_22 { + color=blue + 57 [label="Enter when branch condition "]; + 58 [label="Type operator: ($subj$ is R|SubClass1|)"]; + 59 [label="Exit when branch condition"]; + } + subgraph cluster_23 { + color=blue + 60 [label="Enter when branch condition "]; + 61 [label="Type operator: ($subj$ is R|SubClass2|)"]; + 62 [label="Exit when branch condition"]; + } + 63 [label="Enter when branch result"]; + subgraph cluster_24 { + color=blue + 64 [label="Enter block"]; + 65 [label="Const: String(2)"]; + 66 [label="Exit block"]; + } + 67 [label="Exit when branch result"]; + 68 [label="Enter when branch result"]; + subgraph cluster_25 { + color=blue + 69 [label="Enter block"]; + 70 [label="Access variable R|/p|"]; + 71 [label="Access variable R|/SubClass1.t|"]; + 72 [label="Exit block"]; + } + 73 [label="Exit when branch result"]; + 74 [label="Exit when"]; + } + 75 [label="Access variable R|kotlin/String.length|"]; + 76 [label="Exit block"]; + } + 77 [label="Exit function foo" style="filled" fillcolor=red]; + } + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {44 36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {52}; + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {78}; + 47 -> {48} [color=red]; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {68 60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {74}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {77}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {48} [color=green]; + +} diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt new file mode 100644 index 00000000000..7c551a3deeb --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt @@ -0,0 +1,23 @@ +// ISSUE: KT-39080 +// !DUMP_CFG + +private sealed class Sealed + +private data class SubClass1(val t: String) : Sealed() +private data class SubClass2 : Sealed() + +private fun foo(p: Sealed) { + when (p) { + is SubClass1 -> "".let { + it + } + is SubClass2 -> "" + } + + p.t // should not be resolved, but it has a smartcast to SubClass1 because of the lambda + + when (p) { + is SubClass1 -> p.t + is SubClass2 -> "2" + }.length // should be resolved, but when is not considered as sealed because type of p is not a sealed class +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.txt new file mode 100644 index 00000000000..d6147caedef --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.txt @@ -0,0 +1,52 @@ +FILE: lambdaInWhenBranch.kt + private sealed class Sealed : R|kotlin/Any| { + private constructor(): R|Sealed| { + super() + } + + } + private final data class SubClass1 : R|Sealed| { + public[private] constructor(t: R|kotlin/String|): R|SubClass1| { + super() + } + + public[private] final val t: R|kotlin/String| = R|/t| + public get(): R|kotlin/String| + + public[private] final fun component1(): R|kotlin/String| + + public[private] final fun copy(t: R|kotlin/String| = this@R|/SubClass1|.R|/SubClass1.t|): R|SubClass1| + + } + private final data class SubClass2 : R|Sealed| { + public[private] constructor(): R|SubClass2| { + super() + } + + public[private] final fun copy(): R|SubClass2| + + } + private final fun foo(p: R|Sealed|): R|kotlin/Unit| { + when (R|/p|) { + ($subj$ is R|SubClass1|) -> { + String().R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/String| { + ^ R|/it| + } + ) + } + ($subj$ is R|SubClass2|) -> { + String() + } + } + + R|/p|.# + when (R|/p|) { + ($subj$ is R|SubClass1|) -> { + R|/p|.R|/SubClass1.t| + } + ($subj$ is R|SubClass2|) -> { + String(2) + } + } + .R|kotlin/String.length| + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index ea5bd65c7b8..bfe166fb9f2 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -2095,6 +2095,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/inPlaceLambdas.kt"); } + @TestMetadata("lambdaInWhenBranch.kt") + public void testLambdaInWhenBranch() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt"); + } + @TestMetadata("smartcastOnLambda.kt") public void testSmartcastOnLambda() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/smartcastOnLambda.kt"); diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index fe92557fc21..c06df9ed6ce 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -2095,6 +2095,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/inPlaceLambdas.kt"); } + @TestMetadata("lambdaInWhenBranch.kt") + public void testLambdaInWhenBranch() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt"); + } + @TestMetadata("smartcastOnLambda.kt") public void testSmartcastOnLambda() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/smartcastOnLambda.kt"); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index a7b4731e70f..b823f99eeb3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -493,8 +493,8 @@ abstract class FirDataFlowAnalyzer( graphBuilder.exitWhenBranchResult(whenBranch).mergeIncomingFlow() } - fun exitWhenExpression(whenExpression: FirWhenExpression, callCompleted: Boolean) { - val (whenExitNode, syntheticElseNode, unionNode) = graphBuilder.exitWhenExpression(whenExpression, callCompleted) + fun exitWhenExpression(whenExpression: FirWhenExpression) { + val (whenExitNode, syntheticElseNode) = graphBuilder.exitWhenExpression(whenExpression) if (syntheticElseNode != null) { val previousConditionExitNode = syntheticElseNode.firstPreviousNode as? WhenBranchConditionExitNode // previous node for syntheticElseNode can be not WhenBranchConditionExitNode in case of `when` without any branches @@ -512,7 +512,6 @@ abstract class FirDataFlowAnalyzer( } } whenExitNode.mergeIncomingFlow(updateReceivers = true) - unionNode?.let { unionFlowFromArguments(unionNode) } } // ----------------------------------- While Loop ----------------------------------- @@ -1040,10 +1039,8 @@ abstract class FirDataFlowAnalyzer( } } - fun exitElvis(callCompleted: Boolean) { - val (elvisExitNode, unionNode) = graphBuilder.exitElvis(callCompleted) - elvisExitNode.mergeIncomingFlow() - unionNode?.let { unionFlowFromArguments(it) } + fun exitElvis() { + graphBuilder.exitElvis().mergeIncomingFlow() } // ------------------------------------------------------ Utils ------------------------------------------------------ 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 65feab47dc8..0b376e2ecc3 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 @@ -533,10 +533,7 @@ class ControlFlowGraphBuilder { return node } - fun exitWhenExpression( - whenExpression: FirWhenExpression, - callCompleted: Boolean - ): Triple { + fun exitWhenExpression(whenExpression: FirWhenExpression): Pair { val whenExitNode = whenExitNodes.pop() // exit from last condition node still on stack // we should remove it @@ -549,9 +546,9 @@ class ControlFlowGraphBuilder { } else null whenExitNode.updateDeadStatus() lastNodes.push(whenExitNode) - val (_, unionNode) = processUnionOfArguments(whenExitNode, callCompleted) + dropPostponedLambdasForNonDeterministicCalls() levelCounter-- - return Triple(whenExitNode, syntheticElseBranchNode, unionNode) + return whenExitNode to syntheticElseBranchNode } // ----------------------------------- While Loop ----------------------------------- @@ -870,6 +867,16 @@ class ControlFlowGraphBuilder { return node to unionNode } + /* + * This is needed for some control flow constructions which are resolved as calls (when and elvis) + * For usual call we have invariant that all arguments will be called before function call, but for + * when and elvis only one of arguments will be actually called, so it's illegal to pass data flow info + * from lambda in one of branches + */ + private fun dropPostponedLambdasForNonDeterministicCalls() { + exitsFromCompletedPostponedAnonymousFunctions.clear() + } + private fun processUnionOfArguments( node: CFGNode<*>, callCompleted: Boolean @@ -1010,12 +1017,12 @@ class ControlFlowGraphBuilder { return Triple(lhsExitNode, lhsIsNotNullNode, rhsEnterNode) } - fun exitElvis(callCompleted: Boolean): Pair { + fun exitElvis(): ElvisExitNode { val exitNode = exitElvisCallNodes.pop() addNewSimpleNode(exitNode) exitNode.updateDeadStatus() - val (_, unionNode) = processUnionOfArguments(exitNode, callCompleted) - return exitNode to unionNode + dropPostponedLambdasForNonDeterministicCalls() + return exitNode } // ----------------------------------- Contract description ----------------------------------- diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt index 69f2b950d22..ee0b37686c9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt @@ -68,19 +68,18 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran @Suppress("NAME_SHADOWING") var whenExpression = whenExpression.transformSubject(transformer, ResolutionMode.ContextIndependent) - val callCompleted = when { - whenExpression.branches.isEmpty() -> true + when { + whenExpression.branches.isEmpty() -> {} whenExpression.isOneBranch() -> { whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextIndependent) whenExpression.resultType = whenExpression.branches.first().result.resultType - true } else -> { whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextDependent) whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression) ?: run { whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null) - dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted = true) + dataFlowAnalyzer.exitWhenExpression(whenExpression) whenExpression.resultType = buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Can't resolve when expression", DiagnosticKind.InferenceError) } @@ -90,11 +89,10 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran val expectedTypeRef = data.expectedType val completionResult = callCompleter.completeCall(whenExpression, expectedTypeRef) whenExpression = completionResult.result - completionResult.callCompleted } } whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null) - dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted) + dataFlowAnalyzer.exitWhenExpression(whenExpression) whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive() whenExpression.compose() } @@ -218,21 +216,15 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran dataFlowAnalyzer.exitElvisLhs(elvisCall) elvisCall.transformRhs(transformer, ResolutionMode.ContextDependent) - var callCompleted = false val result = syntheticCallGenerator.generateCalleeForElvisCall(elvisCall)?.let { - val completionResult = callCompleter.completeCall(elvisCall, data.expectedType) - callCompleted = completionResult.callCompleted - completionResult.result - } ?: run { - elvisCall.resultType = buildErrorTypeRef { + callCompleter.completeCall(it, data.expectedType).result + } ?: elvisCall.also { + it.resultType = buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Can't resolve ?: operator call", DiagnosticKind.InferenceError) } - callCompleted = true - elvisCall } - dataFlowAnalyzer.exitElvis(callCompleted) - + dataFlowAnalyzer.exitElvis() return result.compose() } }