From 664a70ec13e393b85e7e012150aadeaece87bdf8 Mon Sep 17 00:00:00 2001 From: pyos Date: Thu, 24 Nov 2022 18:01:32 +0100 Subject: [PATCH] FIR DFA: split flow for postponed lambdas from a single node This removes the need for hacks around the order in which function call arguments are visited, fixes called-in-place lambda arguments for augmented assignment operators, and makes CFG dumps a bit prettier. --- .../resolve/cfg/flowFromTwoInplaceLambdas.dot | 894 +++++++++--------- .../resolve/cfg/lambdaAsReturnOfLambda.dot | 70 +- .../testData/resolve/cfg/lambdas.dot | 168 ++-- .../cfg/postponedLambdaInConstructor.dot | 57 +- .../contracts/fromLibrary/callsInPlace.dot | 176 ++-- .../LocalPropertyAndCapturedWriteCollector.kt | 8 +- .../extended/UnreachableCodeChecker.kt | 1 + .../jetbrains/kotlin/fir/FirCallResolver.kt | 50 +- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 51 +- .../dfa/cfg/ControlFlowGraphBuilder.kt | 95 +- .../dfa/cfg/ControlFlowGraphNodeBuilder.kt | 14 +- .../FirExpressionsResolveTransformer.kt | 104 +- .../kotlin/fir/resolve/dfa/cfg/CFGNode.kt | 9 +- .../fir/resolve/dfa/cfg/CFGNodeRenderer.kt | 6 +- .../dfa/cfg/ControlFlowGraphVisitor.kt | 4 +- .../dfa/cfg/ControlFlowGraphVisitorVoid.kt | 22 +- 16 files changed, 819 insertions(+), 910 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/flowFromTwoInplaceLambdas.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/flowFromTwoInplaceLambdas.dot index 19a419ccd33..05d53bb4fec 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/flowFromTwoInplaceLambdas.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/flowFromTwoInplaceLambdas.dot @@ -69,46 +69,45 @@ digraph flowFromTwoInplaceLambdas_kt { 26 [label="Postponed enter to lambda"]; subgraph cluster_9 { color=blue - 39 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 45 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_10 { color=blue - 40 [label="Enter block"]; - 41 [label="Const: Null(null)"]; - 42 [label="Assignment: R|/p|"]; - 43 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; - 44 [label="Exit block"]; + 46 [label="Enter block"]; + 47 [label="Access variable R|/p|"]; + 48 [label="Smart cast: R|/p|"]; + 49 [label="Access variable #"]; + 50 [label="Const: Int(123)"]; + 51 [label="Exit block"]; } - 45 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 52 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 28 [label="Postponed enter to lambda"]; subgraph cluster_11 { color=blue - 46 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 38 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_12 { color=blue - 47 [label="Enter block"]; - 48 [label="Access variable R|/p|"]; - 49 [label="Smart cast: R|/p|"]; - 50 [label="Access variable #"]; - 51 [label="Const: Int(123)"]; - 52 [label="Exit block"]; + 39 [label="Enter block"]; + 40 [label="Const: Null(null)"]; + 41 [label="Assignment: R|/p|"]; + 42 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; + 43 [label="Exit block"]; } - 53 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 44 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 29 [label="Postponed exit from lambda"]; 27 [label="Postponed exit from lambda"]; - 30 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - 31 [label="Access variable R|/p|"]; - 32 [label="Smart cast: R|/p|"]; - 33 [label="Access variable #"]; - 34 [label="Exit block"]; + 28 [label="Postponed exit from lambda"]; + 29 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 30 [label="Access variable R|/p|"]; + 31 [label="Smart cast: R|/p|"]; + 32 [label="Access variable #"]; + 33 [label="Exit block"]; } - 35 [label="Exit when branch result"]; - 36 [label="Exit when"]; + 34 [label="Exit when branch result"]; + 35 [label="Exit when"]; } - 37 [label="Exit block"]; + 36 [label="Exit block"]; } - 38 [label="Exit function test1" style="filled" fillcolor=red]; + 37 [label="Exit function test1" style="filled" fillcolor=red]; } 13 -> {14}; 14 -> {15}; @@ -120,16 +119,14 @@ digraph flowFromTwoInplaceLambdas_kt { 20 -> {21}; 21 -> {22}; 22 -> {24 23}; - 23 -> {36}; + 23 -> {35}; 24 -> {25}; 25 -> {26}; - 26 -> {28 39}; - 26 -> {27} [style=dotted]; - 26 -> {39} [style=dashed]; - 27 -> {30}; - 28 -> {46 30}; - 28 -> {29} [style=dotted]; - 28 -> {46} [style=dashed]; + 26 -> {38 45 29}; + 26 -> {28 27} [style=dotted]; + 26 -> {38 45} [style=dashed]; + 27 -> {29}; + 28 -> {29}; 29 -> {30}; 30 -> {31}; 31 -> {32}; @@ -138,91 +135,90 @@ digraph flowFromTwoInplaceLambdas_kt { 34 -> {35}; 35 -> {36}; 36 -> {37}; - 37 -> {38}; + 38 -> {39}; 39 -> {40}; 40 -> {41}; 41 -> {42}; 42 -> {43}; 43 -> {44}; - 44 -> {45}; - 45 -> {27}; + 44 -> {28}; + 45 -> {46}; 46 -> {47}; 47 -> {48}; 48 -> {49}; 49 -> {50}; 50 -> {51}; 51 -> {52}; - 52 -> {53}; - 53 -> {29}; + 52 -> {27}; subgraph cluster_13 { color=red - 54 [label="Enter function test1_tail" style="filled" fillcolor=red]; + 53 [label="Enter function test1_tail" style="filled" fillcolor=red]; subgraph cluster_14 { color=blue - 55 [label="Enter block"]; - 56 [label="Access variable R|/x|"]; - 57 [label="Variable declaration: lvar p: R|kotlin/String?|"]; + 54 [label="Enter block"]; + 55 [label="Access variable R|/x|"]; + 56 [label="Variable declaration: lvar p: R|kotlin/String?|"]; subgraph cluster_15 { color=blue - 58 [label="Enter when"]; + 57 [label="Enter when"]; subgraph cluster_16 { color=blue - 59 [label="Enter when branch condition "]; - 60 [label="Access variable R|/p|"]; - 61 [label="Const: Null(null)"]; - 62 [label="Equality operator !="]; - 63 [label="Exit when branch condition"]; + 58 [label="Enter when branch condition "]; + 59 [label="Access variable R|/p|"]; + 60 [label="Const: Null(null)"]; + 61 [label="Equality operator !="]; + 62 [label="Exit when branch condition"]; } - 64 [label="Synthetic else branch"]; - 65 [label="Enter when branch result"]; + 63 [label="Synthetic else branch"]; + 64 [label="Enter when branch result"]; subgraph cluster_17 { color=blue - 66 [label="Enter block"]; - 67 [label="Postponed enter to lambda"]; + 65 [label="Enter block"]; + 66 [label="Postponed enter to lambda"]; subgraph cluster_18 { color=blue - 87 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 85 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_19 { color=blue - 88 [label="Enter block"]; - 89 [label="Access variable R|/p|"]; - 90 [label="Smart cast: R|/p|"]; - 91 [label="Access variable #"]; - 92 [label="Const: Int(123)"]; - 93 [label="Exit block"]; + 86 [label="Enter block"]; + 87 [label="Access variable R|/p|"]; + 88 [label="Smart cast: R|/p|"]; + 89 [label="Access variable #"]; + 90 [label="Const: Int(123)"]; + 91 [label="Exit block"]; } - 94 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 92 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 69 [label="Postponed enter to lambda"]; subgraph cluster_20 { color=blue - 80 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 78 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_21 { color=blue - 81 [label="Enter block"]; - 82 [label="Const: Null(null)"]; - 83 [label="Assignment: R|/p|"]; - 84 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; - 85 [label="Exit block"]; + 79 [label="Enter block"]; + 80 [label="Const: Null(null)"]; + 81 [label="Assignment: R|/p|"]; + 82 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; + 83 [label="Exit block"]; } - 86 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 84 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 70 [label="Postponed exit from lambda"]; + 67 [label="Postponed exit from lambda"]; 68 [label="Postponed exit from lambda"]; - 71 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - 72 [label="Access variable R|/p|"]; - 73 [label="Smart cast: R|/p|"]; - 74 [label="Access variable #"]; - 75 [label="Exit block"]; + 69 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 70 [label="Access variable R|/p|"]; + 71 [label="Smart cast: R|/p|"]; + 72 [label="Access variable #"]; + 73 [label="Exit block"]; } - 76 [label="Exit when branch result"]; - 77 [label="Exit when"]; + 74 [label="Exit when branch result"]; + 75 [label="Exit when"]; } - 78 [label="Exit block"]; + 76 [label="Exit block"]; } - 79 [label="Exit function test1_tail" style="filled" fillcolor=red]; + 77 [label="Exit function test1_tail" style="filled" fillcolor=red]; } + 53 -> {54}; 54 -> {55}; 55 -> {56}; 56 -> {57}; @@ -231,18 +227,16 @@ digraph flowFromTwoInplaceLambdas_kt { 59 -> {60}; 60 -> {61}; 61 -> {62}; - 62 -> {63}; - 63 -> {65 64}; - 64 -> {77}; + 62 -> {64 63}; + 63 -> {75}; + 64 -> {65}; 65 -> {66}; - 66 -> {67}; - 67 -> {69 87}; - 67 -> {68} [style=dotted]; - 67 -> {87} [style=dashed]; - 68 -> {71}; - 69 -> {80 71}; - 69 -> {70} [style=dotted]; - 69 -> {80} [style=dashed]; + 66 -> {78 85 69}; + 66 -> {68 67} [style=dotted]; + 66 -> {78 85} [style=dashed]; + 67 -> {69}; + 68 -> {69}; + 69 -> {70}; 70 -> {71}; 71 -> {72}; 72 -> {73}; @@ -250,594 +244,568 @@ digraph flowFromTwoInplaceLambdas_kt { 74 -> {75}; 75 -> {76}; 76 -> {77}; - 77 -> {78}; 78 -> {79}; + 79 -> {80}; 80 -> {81}; 81 -> {82}; 82 -> {83}; 83 -> {84}; - 84 -> {85}; + 84 -> {68}; 85 -> {86}; - 86 -> {70}; + 86 -> {87}; 87 -> {88}; 88 -> {89}; 89 -> {90}; 90 -> {91}; 91 -> {92}; - 92 -> {93}; - 93 -> {94}; - 94 -> {68}; + 92 -> {67}; subgraph cluster_22 { color=red - 95 [label="Enter function test2" style="filled" fillcolor=red]; + 93 [label="Enter function test2" style="filled" fillcolor=red]; subgraph cluster_23 { color=blue - 96 [label="Enter block"]; - 97 [label="Access variable R|/x|"]; - 98 [label="Variable declaration: lvar p: R|kotlin/Any?|"]; - 99 [label="Access variable R|/p|"]; - 100 [label="Access variable #"]; - 101 [label="Postponed enter to lambda"]; + 94 [label="Enter block"]; + 95 [label="Access variable R|/x|"]; + 96 [label="Variable declaration: lvar p: R|kotlin/Any?|"]; + 97 [label="Access variable R|/p|"]; + 98 [label="Access variable #"]; + 99 [label="Postponed enter to lambda"]; subgraph cluster_24 { color=blue - 116 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 120 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_25 { color=blue - 117 [label="Enter block"]; - 118 [label="Const: Null(null)"]; - 119 [label="Assignment: R|/p|"]; - 120 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; - 121 [label="Exit block"]; + 121 [label="Enter block"]; + 122 [label="Access variable R|/p|"]; + 123 [label="Type operator: (R|/p| as R|kotlin/String|)"]; + 124 [label="Const: Int(123)"]; + 125 [label="Exit block"]; } - 122 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 126 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 103 [label="Postponed enter to lambda"]; subgraph cluster_26 { color=blue - 123 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 113 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_27 { color=blue - 124 [label="Enter block"]; - 125 [label="Access variable R|/p|"]; - 126 [label="Type operator: (R|/p| as R|kotlin/String|)"]; - 127 [label="Const: Int(123)"]; - 128 [label="Exit block"]; + 114 [label="Enter block"]; + 115 [label="Const: Null(null)"]; + 116 [label="Assignment: R|/p|"]; + 117 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; + 118 [label="Exit block"]; } - 129 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 119 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 104 [label="Postponed exit from lambda"]; - 102 [label="Postponed exit from lambda"]; - 105 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 100 [label="Postponed exit from lambda"]; + 101 [label="Postponed exit from lambda"]; + 102 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 103 [label="Access variable R|/p|"]; + 104 [label="Smart cast: R|/p|"]; + 105 [label="Access variable #"]; 106 [label="Access variable R|/p|"]; 107 [label="Smart cast: R|/p|"]; - 108 [label="Access variable #"]; - 109 [label="Access variable R|/p|"]; - 110 [label="Smart cast: R|/p|"]; - 111 [label="Enter safe call"]; - 112 [label="Access variable #"]; - 113 [label="Exit safe call"]; - 114 [label="Exit block"]; + 108 [label="Enter safe call"]; + 109 [label="Access variable #"]; + 110 [label="Exit safe call"]; + 111 [label="Exit block"]; } - 115 [label="Exit function test2" style="filled" fillcolor=red]; + 112 [label="Exit function test2" style="filled" fillcolor=red]; } + 93 -> {94}; + 94 -> {95}; 95 -> {96}; 96 -> {97}; 97 -> {98}; 98 -> {99}; - 99 -> {100}; - 100 -> {101}; - 101 -> {103 116}; - 101 -> {102} [style=dotted]; - 101 -> {116} [style=dashed]; - 102 -> {105}; - 103 -> {123 105}; - 103 -> {104} [style=dotted]; - 103 -> {123} [style=dashed]; + 99 -> {113 120 102}; + 99 -> {101 100} [style=dotted]; + 99 -> {113 120} [style=dashed]; + 100 -> {102}; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; 104 -> {105}; 105 -> {106}; 106 -> {107}; - 107 -> {108}; + 107 -> {108 110}; 108 -> {109}; 109 -> {110}; - 110 -> {111 113}; + 110 -> {111}; 111 -> {112}; - 112 -> {113}; 113 -> {114}; 114 -> {115}; + 115 -> {116}; 116 -> {117}; 117 -> {118}; 118 -> {119}; - 119 -> {120}; + 119 -> {101}; 120 -> {121}; 121 -> {122}; - 122 -> {102}; + 122 -> {123}; 123 -> {124}; 124 -> {125}; 125 -> {126}; - 126 -> {127}; - 127 -> {128}; - 128 -> {129}; - 129 -> {104}; + 126 -> {100}; subgraph cluster_28 { color=red - 130 [label="Enter function test3" style="filled" fillcolor=red]; + 127 [label="Enter function test3" style="filled" fillcolor=red]; subgraph cluster_29 { color=blue - 131 [label="Enter block"]; - 132 [label="Access variable R|/x|"]; - 133 [label="Variable declaration: lvar p: R|kotlin/Any?|"]; - 134 [label="Access variable R|/p|"]; - 135 [label="Access variable #"]; - 136 [label="Postponed enter to lambda"]; + 128 [label="Enter block"]; + 129 [label="Access variable R|/x|"]; + 130 [label="Variable declaration: lvar p: R|kotlin/Any?|"]; + 131 [label="Access variable R|/p|"]; + 132 [label="Access variable #"]; + 133 [label="Postponed enter to lambda"]; subgraph cluster_30 { color=blue - 151 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 154 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_31 { color=blue - 152 [label="Enter block"]; - 153 [label="Const: Null(null)"]; - 154 [label="Assignment: R|/p|"]; - 155 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; - 156 [label="Exit block"]; + 155 [label="Enter block"]; + 156 [label="Const: String()"]; + 157 [label="Assignment: R|/p|"]; + 158 [label="Const: Int(123)"]; + 159 [label="Exit block"]; } - 157 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 160 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 138 [label="Postponed enter to lambda"]; subgraph cluster_32 { color=blue - 158 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 147 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_33 { color=blue - 159 [label="Enter block"]; - 160 [label="Const: String()"]; - 161 [label="Assignment: R|/p|"]; - 162 [label="Const: Int(123)"]; - 163 [label="Exit block"]; + 148 [label="Enter block"]; + 149 [label="Const: Null(null)"]; + 150 [label="Assignment: R|/p|"]; + 151 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; + 152 [label="Exit block"]; } - 164 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 153 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 139 [label="Postponed exit from lambda"]; - 137 [label="Postponed exit from lambda"]; - 140 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - 141 [label="Access variable R|/p|"]; - 142 [label="Smart cast: R|/p|"]; - 143 [label="Access variable #"]; - 144 [label="Access variable R|/p|"]; - 145 [label="Smart cast: R|/p|"]; - 146 [label="Enter safe call"]; - 147 [label="Access variable R|kotlin/String.length|"]; - 148 [label="Exit safe call"]; - 149 [label="Exit block"]; + 134 [label="Postponed exit from lambda"]; + 135 [label="Postponed exit from lambda"]; + 136 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 137 [label="Access variable R|/p|"]; + 138 [label="Smart cast: R|/p|"]; + 139 [label="Access variable #"]; + 140 [label="Access variable R|/p|"]; + 141 [label="Smart cast: R|/p|"]; + 142 [label="Enter safe call"]; + 143 [label="Access variable R|kotlin/String.length|"]; + 144 [label="Exit safe call"]; + 145 [label="Exit block"]; } - 150 [label="Exit function test3" style="filled" fillcolor=red]; + 146 [label="Exit function test3" style="filled" fillcolor=red]; } + 127 -> {128}; + 128 -> {129}; + 129 -> {130}; 130 -> {131}; 131 -> {132}; 132 -> {133}; - 133 -> {134}; - 134 -> {135}; + 133 -> {147 154 136}; + 133 -> {135 134} [style=dotted]; + 133 -> {147 154} [style=dashed]; + 134 -> {136}; 135 -> {136}; - 136 -> {138 151}; - 136 -> {137} [style=dotted]; - 136 -> {151} [style=dashed]; - 137 -> {140}; - 138 -> {158 140}; - 138 -> {139} [style=dotted]; - 138 -> {158} [style=dashed]; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; 139 -> {140}; 140 -> {141}; - 141 -> {142}; + 141 -> {142 144}; 142 -> {143}; 143 -> {144}; 144 -> {145}; - 145 -> {146 148}; - 146 -> {147}; + 145 -> {146}; 147 -> {148}; 148 -> {149}; 149 -> {150}; + 150 -> {151}; 151 -> {152}; 152 -> {153}; - 153 -> {154}; + 153 -> {135}; 154 -> {155}; 155 -> {156}; 156 -> {157}; - 157 -> {137}; + 157 -> {158}; 158 -> {159}; 159 -> {160}; - 160 -> {161}; - 161 -> {162}; - 162 -> {163}; - 163 -> {164}; - 164 -> {139}; + 160 -> {134}; subgraph cluster_34 { color=red - 165 [label="Enter class I1" style="filled" fillcolor=red]; - 166 [label="Exit class I1" style="filled" fillcolor=red]; + 161 [label="Enter class I1" style="filled" fillcolor=red]; + 162 [label="Exit class I1" style="filled" fillcolor=red]; } - 165 -> {166} [color=green]; + 161 -> {162} [color=green]; subgraph cluster_35 { color=red - 167 [label="Enter class I2" style="filled" fillcolor=red]; - 168 [label="Exit class I2" style="filled" fillcolor=red]; + 163 [label="Enter class I2" style="filled" fillcolor=red]; + 164 [label="Exit class I2" style="filled" fillcolor=red]; } - 167 -> {168} [color=green]; + 163 -> {164} [color=green]; subgraph cluster_36 { color=red - 169 [label="Enter function test4" style="filled" fillcolor=red]; + 165 [label="Enter function test4" style="filled" fillcolor=red]; subgraph cluster_37 { color=blue - 170 [label="Enter block"]; - 171 [label="Access variable R|/x|"]; - 172 [label="Access variable #"]; - 173 [label="Access variable R|/x|"]; - 174 [label="Access variable #"]; - 175 [label="Postponed enter to lambda"]; + 166 [label="Enter block"]; + 167 [label="Access variable R|/x|"]; + 168 [label="Access variable #"]; + 169 [label="Access variable R|/x|"]; + 170 [label="Access variable #"]; + 171 [label="Postponed enter to lambda"]; subgraph cluster_38 { color=blue - 188 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 193 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_39 { color=blue - 189 [label="Enter block"]; - 190 [label="Access variable R|/x|"]; - 191 [label="Type operator: (R|/x| as R|I1|)"]; - 192 [label="Access variable R|/x|"]; - 193 [label="Smart cast: R|/x|"]; - 194 [label="Access variable #"]; - 195 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; - 196 [label="Exit block"]; + 194 [label="Enter block"]; + 195 [label="Access variable R|/x|"]; + 196 [label="Type operator: (R|/x| as R|I2|)"]; + 197 [label="Access variable R|/x|"]; + 198 [label="Smart cast: R|/x|"]; + 199 [label="Access variable #"]; + 200 [label="Const: Int(123)"]; + 201 [label="Exit block"]; } - 197 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 202 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 177 [label="Postponed enter to lambda"]; subgraph cluster_40 { color=blue - 198 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 183 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_41 { color=blue - 199 [label="Enter block"]; - 200 [label="Access variable R|/x|"]; - 201 [label="Type operator: (R|/x| as R|I2|)"]; - 202 [label="Access variable R|/x|"]; - 203 [label="Smart cast: R|/x|"]; - 204 [label="Access variable #"]; - 205 [label="Const: Int(123)"]; - 206 [label="Exit block"]; + 184 [label="Enter block"]; + 185 [label="Access variable R|/x|"]; + 186 [label="Type operator: (R|/x| as R|I1|)"]; + 187 [label="Access variable R|/x|"]; + 188 [label="Smart cast: R|/x|"]; + 189 [label="Access variable #"]; + 190 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; + 191 [label="Exit block"]; } - 207 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 192 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 178 [label="Postponed exit from lambda"]; - 176 [label="Postponed exit from lambda"]; - 179 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - 180 [label="Access variable R|/x|"]; - 181 [label="Smart cast: R|/x|"]; - 182 [label="Access variable R|/I1.x|"]; - 183 [label="Access variable R|/x|"]; - 184 [label="Smart cast: R|/x|"]; - 185 [label="Access variable R|/I2.y|"]; - 186 [label="Exit block"]; + 172 [label="Postponed exit from lambda"]; + 173 [label="Postponed exit from lambda"]; + 174 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 175 [label="Access variable R|/x|"]; + 176 [label="Smart cast: R|/x|"]; + 177 [label="Access variable R|/I1.x|"]; + 178 [label="Access variable R|/x|"]; + 179 [label="Smart cast: R|/x|"]; + 180 [label="Access variable R|/I2.y|"]; + 181 [label="Exit block"]; } - 187 [label="Exit function test4" style="filled" fillcolor=red]; + 182 [label="Exit function test4" style="filled" fillcolor=red]; } + 165 -> {166}; + 166 -> {167}; + 167 -> {168}; + 168 -> {169}; 169 -> {170}; 170 -> {171}; - 171 -> {172}; - 172 -> {173}; + 171 -> {183 193 174}; + 171 -> {173 172} [style=dotted]; + 171 -> {183 193} [style=dashed]; + 172 -> {174}; 173 -> {174}; 174 -> {175}; - 175 -> {177 188}; - 175 -> {176} [style=dotted]; - 175 -> {188} [style=dashed]; - 176 -> {179}; - 177 -> {198 179}; - 177 -> {178} [style=dotted]; - 177 -> {198} [style=dashed]; + 175 -> {176}; + 176 -> {177}; + 177 -> {178}; 178 -> {179}; 179 -> {180}; 180 -> {181}; 181 -> {182}; - 182 -> {183}; 183 -> {184}; 184 -> {185}; 185 -> {186}; 186 -> {187}; + 187 -> {188}; 188 -> {189}; 189 -> {190}; 190 -> {191}; 191 -> {192}; - 192 -> {193}; + 192 -> {173}; 193 -> {194}; 194 -> {195}; 195 -> {196}; 196 -> {197}; - 197 -> {176}; + 197 -> {198}; 198 -> {199}; 199 -> {200}; 200 -> {201}; 201 -> {202}; - 202 -> {203}; + 202 -> {172}; + + subgraph cluster_42 { + color=red + 203 [label="Enter function test5" style="filled" fillcolor=red]; + subgraph cluster_43 { + color=blue + 204 [label="Enter block"]; + 205 [label="Access variable R|/x|"]; + 206 [label="Variable declaration: lvar p: R|kotlin/Any?|"]; + 207 [label="Access variable R|/p|"]; + 208 [label="Access variable #"]; + 209 [label="Postponed enter to lambda"]; + subgraph cluster_44 { + color=blue + 230 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_45 { + color=blue + 231 [label="Enter block"]; + 232 [label="Access variable R|/q|"]; + 233 [label="Assignment: R|/p|"]; + 234 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; + 235 [label="Exit block"]; + } + 236 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + subgraph cluster_46 { + color=blue + 223 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_47 { + color=blue + 224 [label="Enter block"]; + 225 [label="Access variable R|/p|"]; + 226 [label="Type operator: (R|/p| as R|kotlin/Int|)"]; + 227 [label="Const: Int(123)"]; + 228 [label="Exit block"]; + } + 229 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 210 [label="Postponed exit from lambda"]; + 211 [label="Postponed exit from lambda"]; + 212 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 213 [label="Access variable R|/p|"]; + 214 [label="Smart cast: R|/p|"]; + 215 [label="Access variable #"]; + 216 [label="Access variable R|/p|"]; + 217 [label="Smart cast: R|/p|"]; + 218 [label="Enter safe call"]; + 219 [label="Access variable R|kotlin/String.length|"]; + 220 [label="Exit safe call"]; + 221 [label="Exit block"]; + } + 222 [label="Exit function test5" style="filled" fillcolor=red]; + } 203 -> {204}; 204 -> {205}; 205 -> {206}; 206 -> {207}; - 207 -> {178}; - - subgraph cluster_42 { - color=red - 208 [label="Enter function test5" style="filled" fillcolor=red]; - subgraph cluster_43 { - color=blue - 209 [label="Enter block"]; - 210 [label="Access variable R|/x|"]; - 211 [label="Variable declaration: lvar p: R|kotlin/Any?|"]; - 212 [label="Access variable R|/p|"]; - 213 [label="Access variable #"]; - 214 [label="Postponed enter to lambda"]; - subgraph cluster_44 { - color=blue - 229 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; - subgraph cluster_45 { - color=blue - 230 [label="Enter block"]; - 231 [label="Access variable R|/p|"]; - 232 [label="Type operator: (R|/p| as R|kotlin/Int|)"]; - 233 [label="Const: Int(123)"]; - 234 [label="Exit block"]; - } - 235 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; - } - 216 [label="Postponed enter to lambda"]; - subgraph cluster_46 { - color=blue - 236 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; - subgraph cluster_47 { - color=blue - 237 [label="Enter block"]; - 238 [label="Access variable R|/q|"]; - 239 [label="Assignment: R|/p|"]; - 240 [label="Function call: R|/n|()" style="filled" fillcolor=yellow]; - 241 [label="Exit block"]; - } - 242 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; - } - 217 [label="Postponed exit from lambda"]; - 215 [label="Postponed exit from lambda"]; - 218 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - 219 [label="Access variable R|/p|"]; - 220 [label="Smart cast: R|/p|"]; - 221 [label="Access variable #"]; - 222 [label="Access variable R|/p|"]; - 223 [label="Smart cast: R|/p|"]; - 224 [label="Enter safe call"]; - 225 [label="Access variable R|kotlin/String.length|"]; - 226 [label="Exit safe call"]; - 227 [label="Exit block"]; - } - 228 [label="Exit function test5" style="filled" fillcolor=red]; - } + 207 -> {208}; 208 -> {209}; - 209 -> {210}; - 210 -> {211}; + 209 -> {223 230 212}; + 209 -> {211 210} [style=dotted]; + 209 -> {223 230} [style=dashed]; + 210 -> {212}; 211 -> {212}; 212 -> {213}; 213 -> {214}; - 214 -> {216 229}; - 214 -> {215} [style=dotted]; - 214 -> {229} [style=dashed]; - 215 -> {218}; - 216 -> {236 218}; - 216 -> {217} [style=dotted]; - 216 -> {236} [style=dashed]; - 217 -> {218}; + 214 -> {215}; + 215 -> {216}; + 216 -> {217}; + 217 -> {218 220}; 218 -> {219}; 219 -> {220}; 220 -> {221}; 221 -> {222}; - 222 -> {223}; - 223 -> {224 226}; + 223 -> {224}; 224 -> {225}; 225 -> {226}; 226 -> {227}; 227 -> {228}; - 229 -> {230}; + 228 -> {229}; + 229 -> {211}; 230 -> {231}; 231 -> {232}; 232 -> {233}; 233 -> {234}; 234 -> {235}; - 235 -> {215}; - 236 -> {237}; - 237 -> {238}; - 238 -> {239}; - 239 -> {240}; - 240 -> {241}; - 241 -> {242}; - 242 -> {217}; + 235 -> {236}; + 236 -> {210}; subgraph cluster_48 { color=red - 243 [label="Enter function test6" style="filled" fillcolor=red]; + 237 [label="Enter function test6" style="filled" fillcolor=red]; subgraph cluster_49 { color=blue - 244 [label="Enter block"]; - 245 [label="Variable declaration: lval x: R|kotlin/String|"]; - 246 [label="Postponed enter to lambda"]; + 238 [label="Enter block"]; + 239 [label="Variable declaration: lval x: R|kotlin/String|"]; + 240 [label="Postponed enter to lambda"]; subgraph cluster_50 { color=blue - 255 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 256 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_51 { color=blue - 256 [label="Enter block"]; - 257 [label="Const: String()"]; - 258 [label="Assignment: R|/x|"]; - 259 [label="Access variable R|/x|"]; - 260 [label="Access variable R|kotlin/String.length|"]; - 261 [label="Exit block"]; + 257 [label="Enter block"]; + 258 [label="Access variable R|/x|"]; + 259 [label="Access variable R|kotlin/String.length|"]; + 260 [label="Exit block"]; } - 262 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 261 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 248 [label="Postponed enter to lambda"]; subgraph cluster_52 { color=blue - 263 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 248 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_53 { color=blue - 264 [label="Enter block"]; - 265 [label="Access variable R|/x|"]; - 266 [label="Access variable R|kotlin/String.length|"]; - 267 [label="Exit block"]; + 249 [label="Enter block"]; + 250 [label="Const: String()"]; + 251 [label="Assignment: R|/x|"]; + 252 [label="Access variable R|/x|"]; + 253 [label="Access variable R|kotlin/String.length|"]; + 254 [label="Exit block"]; } - 268 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 255 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 249 [label="Postponed exit from lambda"]; - 247 [label="Postponed exit from lambda"]; - 250 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - 251 [label="Access variable R|/x|"]; - 252 [label="Access variable R|kotlin/String.length|"]; - 253 [label="Exit block"]; + 241 [label="Postponed exit from lambda"]; + 242 [label="Postponed exit from lambda"]; + 243 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + 244 [label="Access variable R|/x|"]; + 245 [label="Access variable R|kotlin/String.length|"]; + 246 [label="Exit block"]; } - 254 [label="Exit function test6" style="filled" fillcolor=red]; + 247 [label="Exit function test6" style="filled" fillcolor=red]; } + 237 -> {238}; + 238 -> {239}; + 239 -> {240}; + 240 -> {248 256 243}; + 240 -> {242 241} [style=dotted]; + 240 -> {248 256} [style=dashed]; + 241 -> {243}; + 242 -> {243}; 243 -> {244}; 244 -> {245}; 245 -> {246}; - 246 -> {248 255}; - 246 -> {247} [style=dotted]; - 246 -> {255} [style=dashed]; - 247 -> {250}; - 248 -> {263 250}; - 248 -> {249} [style=dotted]; - 248 -> {263} [style=dashed]; + 246 -> {247}; + 248 -> {249}; 249 -> {250}; 250 -> {251}; 251 -> {252}; 252 -> {253}; 253 -> {254}; - 255 -> {256}; + 254 -> {255}; + 255 -> {242}; 256 -> {257}; 257 -> {258}; 258 -> {259}; 259 -> {260}; 260 -> {261}; - 261 -> {262}; - 262 -> {247}; + 261 -> {241}; + + subgraph cluster_54 { + color=red + 262 [label="Enter function test7" style="filled" fillcolor=red]; + subgraph cluster_55 { + color=blue + 263 [label="Enter block"]; + 264 [label="Const: String()"]; + 265 [label="Variable declaration: lval x: R|kotlin/Any?|"]; + 266 [label="Variable declaration: lval y: R|kotlin/Any?|"]; + 267 [label="Postponed enter to lambda"]; + subgraph cluster_56 { + color=blue + 293 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_57 { + color=blue + 294 [label="Enter block"]; + 295 [label="Jump: ^@run2 Unit"]; + 296 [label="Stub" style="filled" fillcolor=gray]; + 297 [label="Exit block" style="filled" fillcolor=gray]; + } + 298 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + subgraph cluster_58 { + color=blue + 287 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_59 { + color=blue + 288 [label="Enter block"]; + 289 [label="Access variable R|/x|"]; + 290 [label="Assignment: R|/y|"]; + 291 [label="Exit block"]; + } + 292 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 268 [label="Postponed exit from lambda"]; + 269 [label="Postponed exit from lambda"]; + 270 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; + subgraph cluster_60 { + color=blue + 271 [label="Enter when"]; + subgraph cluster_61 { + color=blue + 272 [label="Enter when branch condition "]; + 273 [label="Access variable R|/y|"]; + 274 [label="Type operator: (R|/y| is R|kotlin/String|)"]; + 275 [label="Exit when branch condition"]; + } + 276 [label="Synthetic else branch"]; + 277 [label="Enter when branch result"]; + subgraph cluster_62 { + color=blue + 278 [label="Enter block"]; + 279 [label="Access variable R|/x|"]; + 280 [label="Smart cast: R|/x|"]; + 281 [label="Access variable R|kotlin/String.length|"]; + 282 [label="Exit block"]; + } + 283 [label="Exit when branch result"]; + 284 [label="Exit when"]; + } + 285 [label="Exit block"]; + } + 286 [label="Exit function test7" style="filled" fillcolor=red]; + } + 262 -> {263}; 263 -> {264}; 264 -> {265}; 265 -> {266}; 266 -> {267}; - 267 -> {268}; - 268 -> {249}; - - subgraph cluster_54 { - color=red - 269 [label="Enter function test7" style="filled" fillcolor=red]; - subgraph cluster_55 { - color=blue - 270 [label="Enter block"]; - 271 [label="Const: String()"]; - 272 [label="Variable declaration: lval x: R|kotlin/Any?|"]; - 273 [label="Variable declaration: lval y: R|kotlin/Any?|"]; - 274 [label="Postponed enter to lambda"]; - subgraph cluster_56 { - color=blue - 295 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; - subgraph cluster_57 { - color=blue - 296 [label="Enter block"]; - 297 [label="Access variable R|/x|"]; - 298 [label="Assignment: R|/y|"]; - 299 [label="Exit block"]; - } - 300 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; - } - 276 [label="Postponed enter to lambda"]; - subgraph cluster_58 { - color=blue - 301 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; - subgraph cluster_59 { - color=blue - 302 [label="Enter block"]; - 303 [label="Jump: ^@run2 Unit"]; - 304 [label="Stub" style="filled" fillcolor=gray]; - 305 [label="Exit block" style="filled" fillcolor=gray]; - } - 306 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; - } - 277 [label="Postponed exit from lambda"]; - 275 [label="Postponed exit from lambda"]; - 278 [label="Function call: R|/run2|(...)" style="filled" fillcolor=yellow]; - subgraph cluster_60 { - color=blue - 279 [label="Enter when"]; - subgraph cluster_61 { - color=blue - 280 [label="Enter when branch condition "]; - 281 [label="Access variable R|/y|"]; - 282 [label="Type operator: (R|/y| is R|kotlin/String|)"]; - 283 [label="Exit when branch condition"]; - } - 284 [label="Synthetic else branch"]; - 285 [label="Enter when branch result"]; - subgraph cluster_62 { - color=blue - 286 [label="Enter block"]; - 287 [label="Access variable R|/x|"]; - 288 [label="Smart cast: R|/x|"]; - 289 [label="Access variable R|kotlin/String.length|"]; - 290 [label="Exit block"]; - } - 291 [label="Exit when branch result"]; - 292 [label="Exit when"]; - } - 293 [label="Exit block"]; - } - 294 [label="Exit function test7" style="filled" fillcolor=red]; - } + 267 -> {287 293 270}; + 267 -> {269 268} [style=dotted]; + 267 -> {287 293} [style=dashed]; + 268 -> {270}; 269 -> {270}; 270 -> {271}; 271 -> {272}; 272 -> {273}; 273 -> {274}; - 274 -> {276 295}; - 274 -> {275} [style=dotted]; - 274 -> {295} [style=dashed]; - 275 -> {278}; - 276 -> {301 278}; - 276 -> {277} [style=dotted]; - 276 -> {301} [style=dashed]; + 274 -> {275}; + 275 -> {277 276}; + 276 -> {284}; 277 -> {278}; 278 -> {279}; 279 -> {280}; 280 -> {281}; 281 -> {282}; 282 -> {283}; - 283 -> {285 284}; - 284 -> {292}; + 283 -> {284}; + 284 -> {285}; 285 -> {286}; - 286 -> {287}; 287 -> {288}; 288 -> {289}; 289 -> {290}; 290 -> {291}; 291 -> {292}; - 292 -> {293}; + 292 -> {269}; 293 -> {294}; - 295 -> {296}; - 296 -> {297}; - 297 -> {298}; - 298 -> {299}; - 299 -> {300}; - 300 -> {275}; - 301 -> {302}; - 302 -> {303}; - 303 -> {306}; - 303 -> {304} [style=dotted]; - 304 -> {305} [style=dotted]; - 305 -> {306} [style=dotted]; - 306 -> {277}; + 294 -> {295}; + 295 -> {298}; + 295 -> {296} [style=dotted]; + 296 -> {297} [style=dotted]; + 297 -> {298} [style=dotted]; + 298 -> {268}; } diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/lambdaAsReturnOfLambda.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/lambdaAsReturnOfLambda.dot index 9b61ae189c9..ce73647c4d8 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/lambdaAsReturnOfLambda.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/lambdaAsReturnOfLambda.dot @@ -5,26 +5,26 @@ digraph lambdaAsReturnOfLambda_kt { subgraph cluster_0 { color=red - 14 [label="Enter property" style="filled" fillcolor=red]; - 15 [label="Postponed enter to lambda"]; + 13 [label="Enter property" style="filled" fillcolor=red]; + 14 [label="Postponed enter to lambda"]; subgraph cluster_1 { color=blue 0 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_2 { color=blue 1 [label="Enter block"]; - 2 [label="Postponed enter to lambda"]; + 2 [label="Exit anonymous function expression"]; subgraph cluster_3 { color=blue - 8 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 7 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_4 { color=blue - 9 [label="Enter block"]; - 10 [label="Access variable R|/foo|"]; - 11 [label="Function call: R|/bar|(...)" style="filled" fillcolor=yellow]; - 12 [label="Exit block"]; + 8 [label="Enter block"]; + 9 [label="Access variable R|/foo|"]; + 10 [label="Function call: R|/bar|(...)" style="filled" fillcolor=yellow]; + 11 [label="Exit block"]; } - 13 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 12 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } 3 [label="Jump: ^@run lambda@fun (foo: R|kotlin/String|): R|kotlin/Unit| { R|/bar|(R|/foo|) @@ -35,64 +35,62 @@ digraph lambdaAsReturnOfLambda_kt { } 6 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 7 [label="Postponed exit from lambda"]; - 16 [label="Postponed exit from lambda"]; - 17 [label="Function call: R|/run| kotlin/Unit|>(...)" style="filled" fillcolor=yellow]; - 18 [label="Exit property" style="filled" fillcolor=red]; + 15 [label="Postponed exit from lambda"]; + 16 [label="Function call: R|/run| kotlin/Unit|>(...)" style="filled" fillcolor=yellow]; + 17 [label="Exit property" style="filled" fillcolor=red]; } - 14 -> {15}; - 15 -> {16 0 17}; - 15 -> {0} [style=dashed]; + 13 -> {14}; + 14 -> {15 0 16}; + 14 -> {0} [style=dashed]; + 15 -> {16}; 16 -> {17}; - 17 -> {18}; 0 -> {1}; 1 -> {2}; - 2 -> {7 3 8}; - 2 -> {8} [style=dashed]; + 2 -> {3 7}; + 2 -> {7} [style=dashed]; 3 -> {6}; 3 -> {4} [style=dotted]; 4 -> {5} [style=dotted]; 5 -> {6} [style=dotted]; - 7 -> {17}; + 7 -> {8}; 8 -> {9}; 9 -> {10}; 10 -> {11}; 11 -> {12}; - 12 -> {13}; subgraph cluster_5 { color=red - 19 [label="Enter function bar" style="filled" fillcolor=red]; + 18 [label="Enter function bar" style="filled" fillcolor=red]; subgraph cluster_6 { color=blue - 20 [label="Enter block"]; - 21 [label="Exit block"]; + 19 [label="Enter block"]; + 20 [label="Exit block"]; } - 22 [label="Exit function bar" style="filled" fillcolor=red]; + 21 [label="Exit function bar" style="filled" fillcolor=red]; } + 18 -> {19}; 19 -> {20}; 20 -> {21}; - 21 -> {22}; subgraph cluster_7 { color=red - 23 [label="Enter function run" style="filled" fillcolor=red]; + 22 [label="Enter function run" style="filled" fillcolor=red]; subgraph cluster_8 { color=blue - 24 [label="Enter block"]; - 25 [label="Function call: R|/block|.R|SubstitutionOverride|()" style="filled" fillcolor=yellow]; - 26 [label="Jump: ^run R|/block|.R|SubstitutionOverride|()"]; - 27 [label="Stub" style="filled" fillcolor=gray]; - 28 [label="Exit block" style="filled" fillcolor=gray]; + 23 [label="Enter block"]; + 24 [label="Function call: R|/block|.R|SubstitutionOverride|()" style="filled" fillcolor=yellow]; + 25 [label="Jump: ^run R|/block|.R|SubstitutionOverride|()"]; + 26 [label="Stub" style="filled" fillcolor=gray]; + 27 [label="Exit block" style="filled" fillcolor=gray]; } - 29 [label="Exit function run" style="filled" fillcolor=red]; + 28 [label="Exit function run" style="filled" fillcolor=red]; } + 22 -> {23}; 23 -> {24}; 24 -> {25}; - 25 -> {26}; - 26 -> {29}; + 25 -> {28}; + 25 -> {26} [style=dotted]; 26 -> {27} [style=dotted]; 27 -> {28} [style=dotted]; - 28 -> {29} [style=dotted]; } diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/lambdas.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/lambdas.dot index f93b73d60f7..0bfe2a2500a 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/lambdas.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/lambdas.dot @@ -113,30 +113,29 @@ digraph lambdas_kt { subgraph cluster_13 { color=blue 39 [label="Enter block"]; - 40 [label="Local function declaration test_2"]; - 41 [label="Exit anonymous function expression"]; - 42 [label="Variable declaration: lval lambda: R|() -> kotlin/Int|"]; - 43 [label="Exit block"]; + 40 [label="Exit anonymous function expression"]; + 41 [label="Variable declaration: lval lambda: R|() -> kotlin/Int|"]; + 42 [label="Exit block"]; } - 44 [label="Exit when branch result"]; - 45 [label="Exit when"]; + 43 [label="Exit when branch result"]; + 44 [label="Exit when"]; } - 46 [label="Exit block"]; + 45 [label="Exit block"]; } - 47 [label="Exit function test_2" style="filled" fillcolor=red]; + 46 [label="Exit function test_2" style="filled" fillcolor=red]; } subgraph cluster_14 { color=blue - 48 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 47 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_15 { color=blue - 49 [label="Enter block"]; - 50 [label="Access variable R|/x|"]; - 51 [label="Smart cast: R|/x|"]; - 52 [label="Function call: R|/x|.R|kotlin/Int.inc|()" style="filled" fillcolor=yellow]; - 53 [label="Exit block"]; + 48 [label="Enter block"]; + 49 [label="Access variable R|/x|"]; + 50 [label="Smart cast: R|/x|"]; + 51 [label="Function call: R|/x|.R|kotlin/Int.inc|()" style="filled" fillcolor=yellow]; + 52 [label="Exit block"]; } - 54 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 53 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } 30 -> {31}; 31 -> {32}; @@ -145,147 +144,146 @@ digraph lambdas_kt { 34 -> {35}; 35 -> {36}; 36 -> {38 37}; - 37 -> {45}; + 37 -> {44}; 38 -> {39}; 39 -> {40}; - 40 -> {48 41}; - 40 -> {48} [style=dashed]; + 40 -> {47 41}; + 40 -> {47} [style=dashed]; 41 -> {42}; 42 -> {43}; 43 -> {44}; 44 -> {45}; 45 -> {46}; - 46 -> {47}; + 47 -> {48}; 48 -> {49}; 49 -> {50}; 50 -> {51}; 51 -> {52}; 52 -> {53}; - 53 -> {54}; subgraph cluster_16 { color=red - 55 [label="Enter function getInt" style="filled" fillcolor=red]; + 54 [label="Enter function getInt" style="filled" fillcolor=red]; subgraph cluster_17 { color=blue - 56 [label="Enter block"]; - 57 [label="Function call: R|/block|.R|SubstitutionOverride|()" style="filled" fillcolor=yellow]; - 58 [label="Const: Int(1)"]; - 59 [label="Jump: ^getInt Int(1)"]; - 60 [label="Stub" style="filled" fillcolor=gray]; - 61 [label="Exit block" style="filled" fillcolor=gray]; + 55 [label="Enter block"]; + 56 [label="Function call: R|/block|.R|SubstitutionOverride|()" style="filled" fillcolor=yellow]; + 57 [label="Const: Int(1)"]; + 58 [label="Jump: ^getInt Int(1)"]; + 59 [label="Stub" style="filled" fillcolor=gray]; + 60 [label="Exit block" style="filled" fillcolor=gray]; } - 62 [label="Exit function getInt" style="filled" fillcolor=red]; + 61 [label="Exit function getInt" style="filled" fillcolor=red]; } + 54 -> {55}; 55 -> {56}; 56 -> {57}; 57 -> {58}; - 58 -> {59}; - 59 -> {62}; + 58 -> {61}; + 58 -> {59} [style=dotted]; 59 -> {60} [style=dotted]; 60 -> {61} [style=dotted]; - 61 -> {62} [style=dotted]; subgraph cluster_18 { color=red - 63 [label="Enter function test_3" style="filled" fillcolor=red]; + 62 [label="Enter function test_3" style="filled" fillcolor=red]; subgraph cluster_19 { color=blue - 64 [label="Enter block"]; - 65 [label="Postponed enter to lambda"]; + 63 [label="Enter block"]; + 64 [label="Postponed enter to lambda"]; subgraph cluster_20 { color=blue - 72 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 71 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_21 { color=blue - 73 [label="Enter block"]; - 74 [label="Const: Int(1)"]; - 75 [label="Jump: ^test_3 Int(1)"]; - 76 [label="Stub" style="filled" fillcolor=gray]; - 77 [label="Exit block" style="filled" fillcolor=gray]; + 72 [label="Enter block"]; + 73 [label="Const: Int(1)"]; + 74 [label="Jump: ^test_3 Int(1)"]; + 75 [label="Stub" style="filled" fillcolor=gray]; + 76 [label="Exit block" style="filled" fillcolor=gray]; } - 78 [label="Exit function anonymousFunction" style="filled" fillcolor=red style="filled" fillcolor=gray]; + 77 [label="Exit function anonymousFunction" style="filled" fillcolor=red style="filled" fillcolor=gray]; } - 66 [label="Postponed exit from lambda"]; - 67 [label="Function call: R|/getInt|(...)" style="filled" fillcolor=yellow]; - 68 [label="Jump: ^test_3 R|/getInt|( = getInt@fun (): R|kotlin/Unit| { + 65 [label="Postponed exit from lambda"]; + 66 [label="Function call: R|/getInt|(...)" style="filled" fillcolor=yellow]; + 67 [label="Jump: ^test_3 R|/getInt|( = getInt@fun (): R|kotlin/Unit| { ^test_3 Int(1) } )"]; - 69 [label="Stub" style="filled" fillcolor=gray]; - 70 [label="Exit block" style="filled" fillcolor=gray]; + 68 [label="Stub" style="filled" fillcolor=gray]; + 69 [label="Exit block" style="filled" fillcolor=gray]; } - 71 [label="Exit function test_3" style="filled" fillcolor=red]; + 70 [label="Exit function test_3" style="filled" fillcolor=red]; } + 62 -> {63}; 63 -> {64}; - 64 -> {65}; - 65 -> {66 72 67}; - 65 -> {72} [style=dashed]; + 64 -> {65 71 66}; + 64 -> {71} [style=dashed]; + 65 -> {66}; + 65 -> {64} [color=green style=dashed]; 66 -> {67}; - 66 -> {65} [color=green style=dashed]; - 67 -> {68}; - 68 -> {71}; + 67 -> {70}; + 67 -> {68} [style=dotted]; 68 -> {69} [style=dotted]; 69 -> {70} [style=dotted]; - 70 -> {71} [style=dotted]; + 71 -> {72}; 72 -> {73}; 73 -> {74}; - 74 -> {75}; - 75 -> {71}; + 74 -> {70}; + 74 -> {75} [style=dotted]; 75 -> {76} [style=dotted]; 76 -> {77} [style=dotted]; - 77 -> {78} [style=dotted]; - 78 -> {66} [style=dotted]; + 77 -> {65} [style=dotted]; subgraph cluster_22 { color=red - 79 [label="Enter function test_4" style="filled" fillcolor=red]; + 78 [label="Enter function test_4" style="filled" fillcolor=red]; subgraph cluster_23 { color=blue - 80 [label="Enter block"]; - 81 [label="Postponed enter to lambda"]; + 79 [label="Enter block"]; + 80 [label="Postponed enter to lambda"]; subgraph cluster_24 { color=blue - 88 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 87 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_25 { color=blue - 89 [label="Enter block"]; - 90 [label="Const: Int(1)"]; - 91 [label="Jump: ^test_4 Int(1)"]; - 92 [label="Stub" style="filled" fillcolor=gray]; - 93 [label="Exit block" style="filled" fillcolor=gray]; + 88 [label="Enter block"]; + 89 [label="Const: Int(1)"]; + 90 [label="Jump: ^test_4 Int(1)"]; + 91 [label="Stub" style="filled" fillcolor=gray]; + 92 [label="Exit block" style="filled" fillcolor=gray]; } - 94 [label="Exit function anonymousFunction" style="filled" fillcolor=red style="filled" fillcolor=gray]; + 93 [label="Exit function anonymousFunction" style="filled" fillcolor=red style="filled" fillcolor=gray]; } - 82 [label="Postponed exit from lambda"]; - 83 [label="Function call: R|/getInt|(...)" style="filled" fillcolor=yellow]; - 84 [label="Jump: ^test_4 R|/getInt|(block = getInt@fun (): R|kotlin/Unit| { + 81 [label="Postponed exit from lambda"]; + 82 [label="Function call: R|/getInt|(...)" style="filled" fillcolor=yellow]; + 83 [label="Jump: ^test_4 R|/getInt|(block = getInt@fun (): R|kotlin/Unit| { ^test_4 Int(1) } )"]; - 85 [label="Stub" style="filled" fillcolor=gray]; - 86 [label="Exit block" style="filled" fillcolor=gray]; + 84 [label="Stub" style="filled" fillcolor=gray]; + 85 [label="Exit block" style="filled" fillcolor=gray]; } - 87 [label="Exit function test_4" style="filled" fillcolor=red]; + 86 [label="Exit function test_4" style="filled" fillcolor=red]; } + 78 -> {79}; 79 -> {80}; - 80 -> {81}; - 81 -> {82 88 83}; - 81 -> {88} [style=dashed]; + 80 -> {81 87 82}; + 80 -> {87} [style=dashed]; + 81 -> {82}; + 81 -> {80} [color=green style=dashed]; 82 -> {83}; - 82 -> {81} [color=green style=dashed]; - 83 -> {84}; - 84 -> {87}; + 83 -> {86}; + 83 -> {84} [style=dotted]; 84 -> {85} [style=dotted]; 85 -> {86} [style=dotted]; - 86 -> {87} [style=dotted]; + 87 -> {88}; 88 -> {89}; 89 -> {90}; - 90 -> {91}; - 91 -> {87}; + 90 -> {86}; + 90 -> {91} [style=dotted]; 91 -> {92} [style=dotted]; 92 -> {93} [style=dotted]; - 93 -> {94} [style=dotted]; - 94 -> {82} [style=dotted]; + 93 -> {81} [style=dotted]; } diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/postponedLambdaInConstructor.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/postponedLambdaInConstructor.dot index 775771a6baf..f992f691b69 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/postponedLambdaInConstructor.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/postponedLambdaInConstructor.dot @@ -30,23 +30,22 @@ digraph postponedLambdaInConstructor_kt { subgraph cluster_4 { color=blue 13 [label="Enter block"]; - 14 [label="Postponed enter to lambda"]; + 14 [label="Exit anonymous function expression"]; subgraph cluster_5 { color=blue - 18 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 17 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_6 { color=blue - 19 [label="Enter block"]; - 20 [label="Access variable R|/it|"]; - 21 [label="Exit block"]; + 18 [label="Enter block"]; + 19 [label="Access variable R|/it|"]; + 20 [label="Exit block"]; } - 22 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 21 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } 15 [label="Exit block"]; } 16 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 17 [label="Postponed exit from lambda"]; 8 [label="Postponed exit from lambda"]; 9 [label="Function call: R|/s|.R|kotlin/let| kotlin/String|>(...)" style="filled" fillcolor=yellow]; 10 [label="Delegated constructor call: super(...)" style="filled" fillcolor=yellow]; @@ -63,52 +62,50 @@ digraph postponedLambdaInConstructor_kt { 10 -> {11}; 12 -> {13}; 13 -> {14}; - 14 -> {17 15 18}; - 14 -> {18} [style=dashed]; + 14 -> {15 17}; + 14 -> {17} [style=dashed]; 15 -> {16}; 16 -> {8}; - 17 -> {10} [color=red]; - 17 -> {9} [color=green]; + 17 -> {18}; 18 -> {19}; 19 -> {20}; 20 -> {21}; - 21 -> {22}; subgraph cluster_7 { color=red - 23 [label="Enter property" style="filled" fillcolor=red]; - 24 [label="Access variable R|/s|"]; - 25 [label="Exit property" style="filled" fillcolor=red]; + 22 [label="Enter property" style="filled" fillcolor=red]; + 23 [label="Access variable R|/s|"]; + 24 [label="Exit property" style="filled" fillcolor=red]; } + 22 -> {23}; 23 -> {24}; - 24 -> {25}; - 25 -> {33} [color=green]; + 24 -> {32} [color=green]; subgraph cluster_8 { color=red - 26 [label="Enter function foo" style="filled" fillcolor=red]; + 25 [label="Enter function foo" style="filled" fillcolor=red]; subgraph cluster_9 { color=blue - 27 [label="Enter block"]; - 28 [label="Function call: this@R|/B|.R|/B.foo|()" style="filled" fillcolor=yellow]; - 29 [label="Exit block"]; + 26 [label="Enter block"]; + 27 [label="Function call: this@R|/B|.R|/B.foo|()" style="filled" fillcolor=yellow]; + 28 [label="Exit block"]; } - 30 [label="Exit function foo" style="filled" fillcolor=red]; + 29 [label="Exit function foo" style="filled" fillcolor=red]; } + 25 -> {26}; 26 -> {27}; 27 -> {28}; 28 -> {29}; - 29 -> {30}; subgraph cluster_10 { color=red - 31 [label="Enter class B" style="filled" fillcolor=red]; - 32 [label="Part of class initialization"]; - 33 [label="Exit class B" style="filled" fillcolor=red]; + 30 [label="Enter class B" style="filled" fillcolor=red]; + 31 [label="Part of class initialization"]; + 32 [label="Exit class B" style="filled" fillcolor=red]; } - 31 -> {32} [color=green]; - 32 -> {33} [style=dotted]; - 32 -> {23} [color=green]; - 32 -> {23} [style=dashed]; + 30 -> {31} [color=green]; + 31 -> {32} [style=dotted]; + 31 -> {22} [color=green]; + 31 -> {22} [style=dashed]; } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromLibrary/callsInPlace.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromLibrary/callsInPlace.dot index de6f2b3271b..bf69795bfe2 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromLibrary/callsInPlace.dot +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromLibrary/callsInPlace.dot @@ -95,7 +95,8 @@ digraph callsInPlace_kt { subgraph cluster_9 { color=blue 30 [label="Enter block"]; - 31 [label="Postponed enter to lambda"]; + 31 [label="Const: Int(10)"]; + 32 [label="Postponed enter to lambda"]; subgraph cluster_10 { color=blue 37 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; @@ -107,8 +108,7 @@ digraph callsInPlace_kt { } 41 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 33 [label="Const: Int(10)"]; - 32 [label="Postponed exit from lambda"]; + 33 [label="Postponed exit from lambda"]; 34 [label="Function call: R|kotlin/repeat|(...)" style="filled" fillcolor=yellow]; 35 [label="Exit block"]; } @@ -116,18 +116,18 @@ digraph callsInPlace_kt { } 29 -> {30}; 30 -> {31}; - 31 -> {32 33 37}; - 31 -> {37} [style=dashed]; - 32 -> {34}; - 32 -> {31} [color=green style=dashed]; + 31 -> {32}; + 32 -> {33 37 34}; + 32 -> {37} [style=dashed]; 33 -> {34}; + 33 -> {32} [color=green style=dashed]; 34 -> {35}; 35 -> {36}; 37 -> {38}; 38 -> {39}; 39 -> {40}; 40 -> {41}; - 41 -> {32}; + 41 -> {33}; subgraph cluster_12 { color=red @@ -252,167 +252,161 @@ digraph callsInPlace_kt { 84 [label="Postponed enter to lambda"]; subgraph cluster_24 { color=blue - 96 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 95 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_25 { color=blue - 97 [label="Enter block"]; - 98 [label="Const: String(test_6_2)"]; - 99 [label="Exit block"]; + 96 [label="Enter block"]; + 97 [label="Const: String(test_6_2)"]; + 98 [label="Exit block"]; } - 100 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 99 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 86 [label="Postponed enter to lambda"]; subgraph cluster_26 { color=blue - 91 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 90 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_27 { color=blue - 92 [label="Enter block"]; - 93 [label="Const: String(test_6_1)"]; - 94 [label="Exit block"]; + 91 [label="Enter block"]; + 92 [label="Const: String(test_6_1)"]; + 93 [label="Exit block"]; } - 95 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 94 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 87 [label="Postponed exit from lambda"]; 85 [label="Postponed exit from lambda"]; - 88 [label="Function call: R|/myRun|(...)" style="filled" fillcolor=yellow]; - 89 [label="Exit block"]; + 86 [label="Postponed exit from lambda"]; + 87 [label="Function call: R|/myRun|(...)" style="filled" fillcolor=yellow]; + 88 [label="Exit block"]; } - 90 [label="Exit function test_6" style="filled" fillcolor=red]; + 89 [label="Exit function test_6" style="filled" fillcolor=red]; } 82 -> {83}; 83 -> {84}; - 84 -> {85 86 96}; - 84 -> {96} [style=dashed]; - 85 -> {88}; + 84 -> {86 85 90 95 87}; + 84 -> {90 95} [style=dashed]; + 85 -> {87}; 85 -> {84} [color=green style=dashed]; - 86 -> {87 91 88}; - 86 -> {91} [style=dashed]; + 86 -> {87}; + 86 -> {84} [color=green style=dashed]; 87 -> {88}; - 87 -> {86} [color=green style=dashed]; 88 -> {89}; - 89 -> {90}; + 90 -> {91}; 91 -> {92}; 92 -> {93}; 93 -> {94}; - 94 -> {95}; - 95 -> {87}; + 94 -> {86}; + 95 -> {96}; 96 -> {97}; 97 -> {98}; 98 -> {99}; - 99 -> {100}; - 100 -> {85}; + 99 -> {85}; subgraph cluster_28 { color=red - 101 [label="Enter function test_7" style="filled" fillcolor=red]; + 100 [label="Enter function test_7" style="filled" fillcolor=red]; subgraph cluster_29 { color=blue - 102 [label="Enter block"]; - 103 [label="Postponed enter to lambda"]; + 101 [label="Enter block"]; + 102 [label="Postponed enter to lambda"]; subgraph cluster_30 { color=blue - 110 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 113 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_31 { color=blue - 111 [label="Enter block"]; - 112 [label="Const: String(test_7_2)"]; - 113 [label="Exit block"]; + 114 [label="Enter block"]; + 115 [label="Const: String(test_7_1)"]; + 116 [label="Exit block"]; } - 114 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 117 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 105 [label="Postponed enter to lambda"]; subgraph cluster_32 { color=blue - 115 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 108 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_33 { color=blue - 116 [label="Enter block"]; - 117 [label="Const: String(test_7_1)"]; - 118 [label="Exit block"]; + 109 [label="Enter block"]; + 110 [label="Const: String(test_7_2)"]; + 111 [label="Exit block"]; } - 119 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 112 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 106 [label="Postponed exit from lambda"]; + 103 [label="Postponed exit from lambda"]; 104 [label="Postponed exit from lambda"]; - 107 [label="Function call: R|/myRun|(...)" style="filled" fillcolor=yellow]; - 108 [label="Exit block"]; + 105 [label="Function call: R|/myRun|(...)" style="filled" fillcolor=yellow]; + 106 [label="Exit block"]; } - 109 [label="Exit function test_7" style="filled" fillcolor=red]; + 107 [label="Exit function test_7" style="filled" fillcolor=red]; } + 100 -> {101}; 101 -> {102}; - 102 -> {103}; - 103 -> {104 105 110}; - 103 -> {110} [style=dashed]; - 104 -> {107}; - 104 -> {103} [color=green style=dashed]; - 105 -> {106 115 107}; - 105 -> {115} [style=dashed]; + 102 -> {104 103 108 113 105}; + 102 -> {108 113} [style=dashed]; + 103 -> {105}; + 103 -> {102} [color=green style=dashed]; + 104 -> {105}; + 104 -> {102} [color=green style=dashed]; + 105 -> {106}; 106 -> {107}; - 106 -> {105} [color=green style=dashed]; - 107 -> {108}; 108 -> {109}; + 109 -> {110}; 110 -> {111}; 111 -> {112}; - 112 -> {113}; + 112 -> {104}; 113 -> {114}; - 114 -> {104}; + 114 -> {115}; 115 -> {116}; 116 -> {117}; - 117 -> {118}; - 118 -> {119}; - 119 -> {106}; + 117 -> {103}; subgraph cluster_34 { color=red - 120 [label="Enter function myDummyRun" style="filled" fillcolor=red]; + 118 [label="Enter function myDummyRun" style="filled" fillcolor=red]; subgraph cluster_35 { color=blue - 121 [label="Enter block"]; - 122 [label="Function call: R|/block|.R|SubstitutionOverride|()" style="filled" fillcolor=yellow]; - 123 [label="Exit block"]; + 119 [label="Enter block"]; + 120 [label="Function call: R|/block|.R|SubstitutionOverride|()" style="filled" fillcolor=yellow]; + 121 [label="Exit block"]; } - 124 [label="Exit function myDummyRun" style="filled" fillcolor=red]; + 122 [label="Exit function myDummyRun" style="filled" fillcolor=red]; } + 118 -> {119}; + 119 -> {120}; 120 -> {121}; 121 -> {122}; - 122 -> {123}; - 123 -> {124}; subgraph cluster_36 { color=red - 125 [label="Enter function test_8" style="filled" fillcolor=red]; + 123 [label="Enter function test_8" style="filled" fillcolor=red]; subgraph cluster_37 { color=blue - 126 [label="Enter block"]; - 127 [label="Postponed enter to lambda"]; + 124 [label="Enter block"]; + 125 [label="Postponed enter to lambda"]; subgraph cluster_38 { color=blue - 132 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 130 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_39 { color=blue - 133 [label="Enter block"]; - 134 [label="Const: String(test_8)"]; - 135 [label="Exit block"]; + 131 [label="Enter block"]; + 132 [label="Const: String(test_8)"]; + 133 [label="Exit block"]; } - 136 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 134 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 128 [label="Postponed exit from lambda"]; - 129 [label="Function call: R|/myDummyRun|(...)" style="filled" fillcolor=yellow]; - 130 [label="Exit block"]; + 126 [label="Postponed exit from lambda"]; + 127 [label="Function call: R|/myDummyRun|(...)" style="filled" fillcolor=yellow]; + 128 [label="Exit block"]; } - 131 [label="Exit function test_8" style="filled" fillcolor=red]; + 129 [label="Exit function test_8" style="filled" fillcolor=red]; } - 125 -> {126}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126 130 127}; + 125 -> {130} [style=dashed]; 126 -> {127}; - 127 -> {128 132 129}; - 127 -> {132} [style=dashed]; + 127 -> {128}; 128 -> {129}; - 129 -> {130}; 130 -> {131}; + 131 -> {132}; 132 -> {133}; 133 -> {134}; - 134 -> {135}; - 135 -> {136}; } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt index d7d955b6f76..22ce3a110ca 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt @@ -39,11 +39,15 @@ class LocalPropertyAndCapturedWriteCollector private constructor() : ControlFlow symbols[node.fir.symbol] = lambdaOrLocalFunctionStack.lastOrNull() == null } - override fun visitPostponedLambdaEnterNode(node: PostponedLambdaEnterNode) { + override fun visitSplitPostponedLambdasNode(node: SplitPostponedLambdasNode) { + lambdaOrLocalFunctionStack.addAll(node.lambdas) + } + + override fun visitAnonymousFunctionExpressionNode(node: AnonymousFunctionExpressionNode) { lambdaOrLocalFunctionStack.add(node.fir.anonymousFunction) } - override fun visitLocalFunctionDeclarationNode(node: LocalFunctionDeclarationNode, data: Nothing?) { + override fun visitLocalFunctionDeclarationNode(node: LocalFunctionDeclarationNode) { lambdaOrLocalFunctionStack.add(node.fir) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnreachableCodeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnreachableCodeChecker.kt index 33135147f58..13c3f383b4e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnreachableCodeChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnreachableCodeChecker.kt @@ -49,6 +49,7 @@ object UnreachableCodeChecker : FirControlFlowChecker() { val skipType = this is ExitNodeMarker || this is EnterNodeMarker || this is StubNode || + this is SplitPostponedLambdasNode || this is BinaryOrExitLeftOperandNode || this is BinaryOrEnterRightOperandNode || this is BinaryAndExitLeftOperandNode || diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 12a1977ee40..d12ce0b494f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -68,21 +68,7 @@ class FirCallResolver( val conflictResolver: ConeCallConflictResolver = session.callConflictResolverFactory.create(TypeSpecificityComparator.NONE, session.inferenceComponents, components) - @PrivateForInline - var needTransformArguments: Boolean = true - - @OptIn(PrivateForInline::class) fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall): FirFunctionCall { - @Suppress("NAME_SHADOWING") - val functionCall = if (needTransformArguments) { - functionCall.transformExplicitReceiver().also { - components.dataFlowAnalyzer.enterQualifiedAccessExpression() - functionCall.replaceArgumentList(functionCall.argumentList.transform(transformer, ResolutionMode.ContextDependent)) - } - } else { - functionCall - } - val name = functionCall.calleeReference.name val result = collectCandidates(functionCall, name, origin = functionCall.origin) @@ -132,29 +118,6 @@ class FirCallResolver( return resultFunctionCall } - private inline fun Q.transformExplicitReceiver(): Q { - val explicitReceiver = - explicitReceiver as? FirQualifiedAccessExpression - ?: return transformExplicitReceiver(transformer, ResolutionMode.ReceiverResolution) as Q - - (explicitReceiver.calleeReference as? FirSuperReference)?.let { - transformer.transformSuperReceiver(it, explicitReceiver, this) - return this - } - - if (explicitReceiver is FirPropertyAccessExpression) { - this.replaceExplicitReceiver( - transformer.transformQualifiedAccessExpression( - explicitReceiver, ResolutionMode.ReceiverResolution, - isUsedAsReceiver = true - ) as FirExpression - ) - return this - } - - return transformExplicitReceiver(transformer, ResolutionMode.ReceiverResolution) as Q - } - private data class ResolutionResult( val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection, ) @@ -249,7 +212,7 @@ class FirCallResolver( val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess @Suppress("NAME_SHADOWING") - val qualifiedAccess = qualifiedAccess.transformExplicitReceiver() + val qualifiedAccess = transformer.transformExplicitReceiver(qualifiedAccess) val nonFatalDiagnosticFromExpression = (qualifiedAccess as? FirPropertyAccessExpression)?.nonFatalDiagnostics val basicResult by lazy(LazyThreadSafetyMode.NONE) { @@ -605,17 +568,6 @@ class FirCallResolver( return ResolutionResult(callInfo, applicability, listOf(candidate)) } - @OptIn(PrivateForInline::class) - inline fun withNoArgumentsTransform(block: () -> T): T { - val oldValue = needTransformArguments - needTransformArguments = false - return try { - block() - } finally { - needTransformArguments = oldValue - } - } - private fun selectDelegatingConstructorCall( call: FirDelegatedConstructorCall, name: Name, result: CandidateCollector, callInfo: CallInfo ): FirDelegatedConstructorCall { 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 fa2b4cc4cf9..73da6eab2f6 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 @@ -152,7 +152,7 @@ abstract class FirDataFlowAnalyzer( if (function is FirDefaultPropertyAccessor) return val (localFunctionNode, functionEnterNode) = if (function is FirAnonymousFunction) { - graphBuilder.enterAnonymousFunction(function) + null to graphBuilder.enterAnonymousFunction(function) } else { graphBuilder.enterFunction(function) } @@ -201,12 +201,8 @@ abstract class FirDataFlowAnalyzer( // ----------------------------------- Anonymous function ----------------------------------- - fun visitPostponedAnonymousFunction(anonymousFunctionExpression: FirAnonymousFunctionExpression) { - graphBuilder.visitPostponedAnonymousFunction(anonymousFunctionExpression).mergeIncomingFlow() - } - - fun exitAnonymousFunctionExpression(anonymousFunctionExpression: FirAnonymousFunctionExpression) { - graphBuilder.exitAnonymousFunctionExpression(anonymousFunctionExpression).mergeIncomingFlow() + fun enterAnonymousFunctionExpression(anonymousFunctionExpression: FirAnonymousFunctionExpression) { + graphBuilder.enterAnonymousFunctionExpression(anonymousFunctionExpression)?.mergeIncomingFlow() } // ----------------------------------- Classes ----------------------------------- @@ -739,9 +735,6 @@ abstract class FirDataFlowAnalyzer( // ----------------------------------- Resolvable call ----------------------------------- - // Intentionally left empty for potential future needs (call sites are preserved) - fun enterQualifiedAccessExpression() {} - fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) { graphBuilder.exitQualifiedAccessExpression(qualifiedAccessExpression).mergeIncomingFlow { flow -> processConditionalContract(flow, qualifiedAccessExpression) @@ -780,50 +773,26 @@ abstract class FirDataFlowAnalyzer( graphBuilder.exitResolvedQualifierNode(resolvedQualifier).mergeIncomingFlow() } - private var resolvingAugmentedAssignmentOptions: Boolean = false - - // The expected sequence of calls for augmented assignment: - // 1. enterAugmentedAssignmentCall() - // 2. resolve arguments - // 3. enterSelectAugmentedAssignmentCall() - // 4. resolve all options for calls in context-independent mode - // 5. exitSelectAugmentedAssignmentCall() - // 6. complete the chosen version - // 7. exitFunctionCall(top-level call in the chosen option) - fun enterAugmentedAssignmentCall() { + fun enterCallArguments(call: FirStatement, arguments: List) { + val lambdas = arguments.mapNotNull { it.unwrapAnonymousFunctionExpression() } + context.variableAssignmentAnalyzer.enterFunctionCall(lambdas) graphBuilder.enterCall() - context.variableAssignmentAnalyzer.enterFunctionCall(emptyList()) + graphBuilder.enterCallArguments(call, lambdas) } - fun enterSelectAugmentedAssignmentCall() { - assert(!resolvingAugmentedAssignmentOptions) { "resolving augmented assignment while resolving augmented assignment?" } - resolvingAugmentedAssignmentOptions = true - } - - fun exitSelectAugmentedAssignmentCall() { - assert(resolvingAugmentedAssignmentOptions) { "no enterSelectAugmentedAssignmentCall before exitSelectAugmentedAssignmentCall" } - resolvingAugmentedAssignmentOptions = false - } - - fun enterFunctionCall(functionCall: FirFunctionCall) { - if (resolvingAugmentedAssignmentOptions) return // shouldn't be any lambda arguments anyway, they're visited before that - context.variableAssignmentAnalyzer.enterFunctionCall(functionCall.arguments.mapNotNull { it.unwrapAnonymousFunctionExpression() }) - graphBuilder.enterCall() + fun exitCallArguments() { + graphBuilder.exitCallArguments()?.mergeIncomingFlow() } fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean) { - if (resolvingAugmentedAssignmentOptions) return context.variableAssignmentAnalyzer.exitFunctionCall(callCompleted) graphBuilder.exitFunctionCall(functionCall, callCompleted).mergeIncomingFlow { processConditionalContract(it, functionCall) } } - fun enterDelegatedConstructorCall() { - graphBuilder.enterCall() - } - fun exitDelegatedConstructorCall(call: FirDelegatedConstructorCall, callCompleted: Boolean) { + context.variableAssignmentAnalyzer.exitFunctionCall(callCompleted) graphBuilder.exitDelegatedConstructorCall(call, callCompleted).mergeIncomingFlow() } 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 c0de1e6ed3e..aeacb40d6ce 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 @@ -61,14 +61,15 @@ class ControlFlowGraphBuilder { //return jumps via finally blocks, target -> jumps private val nonDirectJumps: ListMultimap, CFGNode<*>> = listMultimapOf() + private val argumentListSplitNodes: Stack = stackOf() private val postponedAnonymousFunctionNodes = - mutableMapOf, Pair>() + mutableMapOf, Pair, PostponedLambdaExitNode?>>() private val postponedLambdaExits: Stack, EdgeKind>>> = stackOf() private val loopConditionEnterNodes: NodeStorage = NodeStorage() private val loopExitNodes: NodeStorage = NodeStorage() - private val whenExitNodes: NodeStorage = NodeStorage() + private val whenExitNodes: Stack = stackOf() private val binaryLogicExpressionExitNodes: Stack> = stackOf() @@ -236,23 +237,28 @@ class ControlFlowGraphBuilder { // for them may not have been computed yet. Instead, these edges are redirected // into the outer call. The outermost call *has* to be completed, so at some point // all data will be unified in a single call node. - fun visitPostponedAnonymousFunction(anonymousFunctionExpression: FirAnonymousFunctionExpression): PostponedLambdaEnterNode { - // TODO: should only have 1 enter node for all lambdas in a single call. - val enterNode = createPostponedLambdaEnterNode(anonymousFunctionExpression) - val exitNode = createPostponedLambdaExitNode(anonymousFunctionExpression) + fun enterAnonymousFunctionExpression(anonymousFunctionExpression: FirAnonymousFunctionExpression): AnonymousFunctionExpressionNode? { val symbol = anonymousFunctionExpression.anonymousFunction.symbol - postponedAnonymousFunctionNodes[symbol] = enterNode to exitNode - addNewSimpleNode(enterNode) + val enterNode = postponedAnonymousFunctionNodes[symbol]?.first + ?: return createAnonymousFunctionExpressionNode(anonymousFunctionExpression).also { + addNewSimpleNode(it) + // Not in an argument list, won't be called in-place, don't need an exit node. + postponedAnonymousFunctionNodes[symbol] = it to null + } + val exitNode = createPostponedLambdaExitNode(anonymousFunctionExpression) + // Ideally we'd only add this edge in `exitAnonymousFunction`, but unfortunately it's possible + // that the function won't be visited for so long, we'll exit `currentGraph` before that. + // When exiting a graph, all nodes in it are topologically sorted, so unless we add some edge + // here, `exitNode` will be dropped from the node list. Oops. TODO: fix `orderNodes` someday. addEdge(enterNode, exitNode) + postponedAnonymousFunctionNodes[symbol] = enterNode to exitNode postponedLambdaExits.top().add(exitNode to EdgeKind.Forward) - return enterNode + return null } - fun enterAnonymousFunction(anonymousFunction: FirAnonymousFunction): Pair { + fun enterAnonymousFunction(anonymousFunction: FirAnonymousFunction): FunctionEnterNode { val symbol = anonymousFunction.symbol - val flowSourceNode = postponedAnonymousFunctionNodes[symbol]?.first - ?: createLocalFunctionDeclarationNode(anonymousFunction).also { addNewSimpleNode(it) } - + val flowSourceNode = postponedAnonymousFunctionNodes.getValue(symbol).first pushGraph(ControlFlowGraph(anonymousFunction, "", ControlFlowGraph.Kind.AnonymousFunction), Mode.Function) val enterNode = createFunctionEnterNode(anonymousFunction) val exitNode = createFunctionExitNode(anonymousFunction) @@ -260,10 +266,9 @@ class ControlFlowGraphBuilder { if (!anonymousFunction.invocationKind.isInPlace) { exitTargetsForTry.push(exitNode) } - addEdge(flowSourceNode, enterNode) lastNodes.push(enterNode) - return (flowSourceNode as? LocalFunctionDeclarationNode) to enterNode + return enterNode } fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): Triple { @@ -276,41 +281,41 @@ class ControlFlowGraphBuilder { popAndAddEdge(exitNode) exitNode.updateDeadStatus() - val graph = popGraph().also { graph -> - assert(graph.declaration == anonymousFunction) - assert(graph.exitNode == exitNode) - } + val graph = popGraph() + assert(graph.declaration == anonymousFunction) + assert(graph.exitNode == exitNode) - val (postponedEnterNode, postponedExitNode) = postponedAnonymousFunctionNodes.remove(symbol) - ?: return Triple(exitNode, null, graph).also { currentGraph.addSubGraph(graph) } + val (splitNode, postponedExitNode) = postponedAnonymousFunctionNodes.remove(symbol)!! + splitNode.addSubGraph(graph) + // May not be the current graph: `select(run { run { generic() } }, 1)` + splitNode.owner.addSubGraph(graph) val invocationKind = anonymousFunction.invocationKind + if (postponedExitNode == null) { + // Postponed exit node was needed so we could create lambda->call edges without having the subgraph ready. If it + // doesn't exist, then we probably can't do that anymore, and the lambda won't be called-in-place in the CFG. + // TODO: verify & enable this assertion? + //assert(invocationKind?.canBeVisited() != true) { "no exit node for calledInPlace($invocationKind) lambda" } + return Triple(exitNode, null, graph) + } + // Lambdas not called in-place behave as if called never, but with extra invalidation of all smart casts // for all variables that they reassign. That second part is handled by `FirDataFlowAnalyzer`. + val isDefinitelyVisited = invocationKind?.isDefinitelyVisited() == true + if (isDefinitelyVisited || splitNode.isDead) { + // The edge that was added as a hack to enforce ordering of nodes needs to be marked as dead if this lambda is never + // skipped. Or if the entry node is dead, because at the time we added the hack-edge we didn't know that. + CFGNode.addJustKindEdge(splitNode, postponedExitNode, EdgeKind.DeadForward, propagateDeadness = !isDefinitelyVisited) + } if (invocationKind?.canBeVisited() == true) { - addEdge(exitNode, postponedExitNode, propagateDeadness = invocationKind.isDefinitelyVisited()) - if (invocationKind.isDefinitelyVisited()) { - // We had to create this edge so that if the lambda is postponed for so long that we exit the subgraph - // before visiting it, `orderNodes` can still find an ordering. Now we can kill it. - CFGNode.addJustKindEdge(postponedEnterNode, postponedExitNode, EdgeKind.DeadForward, propagateDeadness = false) - } + addEdge(exitNode, postponedExitNode, propagateDeadness = isDefinitelyVisited) if (invocationKind.canBeRevisited()) { - addBackEdge(postponedExitNode, postponedEnterNode) + addBackEdge(postponedExitNode, splitNode, label = LoopBackPath) } } - - postponedEnterNode.addSubGraph(graph) - // May not be the current graph: `nearestCompletedCall(run { run { generic() } }, 1)` - postponedEnterNode.owner.addSubGraph(graph) return Triple(exitNode, postponedExitNode, graph) } - fun exitAnonymousFunctionExpression(anonymousFunctionExpression: FirAnonymousFunctionExpression): AnonymousFunctionExpressionExitNode { - return createAnonymousFunctionExpressionExitNode(anonymousFunctionExpression).also { - addNewSimpleNode(it) - } - } - private fun splitDataFlowForPostponedLambdas() { postponedLambdaExits.push(mutableListOf()) } @@ -1084,6 +1089,20 @@ class ControlFlowGraphBuilder { splitDataFlowForPostponedLambdas() } + fun enterCallArguments(fir: FirStatement, anonymousFunctions: List) { + if (anonymousFunctions.isEmpty()) { + argumentListSplitNodes.push(null) + } else { + val splitNode = createSplitPostponedLambdasNode(fir, anonymousFunctions) + anonymousFunctions.associateTo(postponedAnonymousFunctionNodes) { it.symbol to (splitNode to null) } + argumentListSplitNodes.push(splitNode) + } + } + + fun exitCallArguments(): SplitPostponedLambdasNode? { + return argumentListSplitNodes.pop()?.also { addNewSimpleNode(it) } + } + fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode { levelCounter-- val returnsNothing = functionCall.resultType.isNothing diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt index 7641a71b1b5..17592ad753f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt @@ -223,11 +223,14 @@ fun ControlFlowGraphBuilder.createEnterSafeCallNode(fir: FirSafeCallExpression): fun ControlFlowGraphBuilder.createPostponedLambdaExitNode(fir: FirAnonymousFunctionExpression): PostponedLambdaExitNode = PostponedLambdaExitNode(currentGraph, fir, levelCounter, createId()) -fun ControlFlowGraphBuilder.createPostponedLambdaEnterNode(fir: FirAnonymousFunctionExpression): PostponedLambdaEnterNode = - PostponedLambdaEnterNode(currentGraph, fir, levelCounter, createId()) +fun ControlFlowGraphBuilder.createSplitPostponedLambdasNode(fir: FirStatement, lambdas: List): SplitPostponedLambdasNode = + SplitPostponedLambdasNode(currentGraph, fir, lambdas, levelCounter, createId()) -fun ControlFlowGraphBuilder.createAnonymousFunctionExpressionExitNode(fir: FirAnonymousFunctionExpression): AnonymousFunctionExpressionExitNode = - AnonymousFunctionExpressionExitNode(currentGraph, fir, levelCounter, createId()) +fun ControlFlowGraphBuilder.createMergePostponedLambdaExitsNode(fir: FirElement): MergePostponedLambdaExitsNode = + MergePostponedLambdaExitsNode(currentGraph, fir, levelCounter, createId()) + +fun ControlFlowGraphBuilder.createAnonymousFunctionExpressionNode(fir: FirAnonymousFunctionExpression): AnonymousFunctionExpressionNode = + AnonymousFunctionExpressionNode(currentGraph, fir, levelCounter, createId()) fun ControlFlowGraphBuilder.createAnonymousObjectEnterNode(fir: FirAnonymousObject): AnonymousObjectEnterNode = AnonymousObjectEnterNode(currentGraph, fir, levelCounter, createId()) @@ -244,9 +247,6 @@ fun ControlFlowGraphBuilder.createScriptEnterNode(fir: FirScript): ScriptEnterNo fun ControlFlowGraphBuilder.createScriptExitNode(fir: FirScript): ScriptExitNode = ScriptExitNode(currentGraph, fir, levelCounter, createId()) -fun ControlFlowGraphBuilder.createMergePostponedLambdaExitsNode(fir: FirElement): MergePostponedLambdaExitsNode = - MergePostponedLambdaExitsNode(currentGraph, fir, levelCounter, createId()) - fun ControlFlowGraphBuilder.createClassEnterNode(fir: FirClass): ClassEnterNode = ClassEnterNode(currentGraph, fir, levelCounter, createId()) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index d3b9d48fe3b..6dbb1feeab9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -164,8 +164,6 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT } when (result) { is FirQualifiedAccessExpression -> { - // TODO: Is it really needed? - dataFlowAnalyzer.enterQualifiedAccessExpression() dataFlowAnalyzer.exitQualifiedAccessExpression(result) result = components.transformQualifiedAccessUsingSmartcastInfo(result) if (result is FirSmartCastExpression) { @@ -179,6 +177,27 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT return result } + fun transformExplicitReceiver(qualifiedAccessExpression: Q): Q { + val explicitReceiver = qualifiedAccessExpression.explicitReceiver as? FirQualifiedAccessExpression + if (explicitReceiver is FirQualifiedAccessExpression) { + val superReference = explicitReceiver.calleeReference as? FirSuperReference + if (superReference != null) { + transformSuperReceiver(superReference, explicitReceiver, qualifiedAccessExpression) + return qualifiedAccessExpression + } + } + if (explicitReceiver is FirPropertyAccessExpression) { + qualifiedAccessExpression.replaceExplicitReceiver( + transformQualifiedAccessExpression( + explicitReceiver, ResolutionMode.ReceiverResolution, isUsedAsReceiver = true + ) as FirExpression + ) + return qualifiedAccessExpression + } + @Suppress("UNCHECKED_CAST") + return qualifiedAccessExpression.transformExplicitReceiver(transformer, ResolutionMode.ReceiverResolution) as Q + } + override fun transformPropertyAccessExpression( propertyAccessExpression: FirPropertyAccessExpression, data: ResolutionMode @@ -379,11 +398,19 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT functionCall.transformAnnotations(transformer, data) functionCall.replaceLambdaArgumentInvocationKinds(session) functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent) - dataFlowAnalyzer.enterFunctionCall(functionCall) val (completeInference, callCompleted) = try { val initialExplicitReceiver = functionCall.explicitReceiver - val resultExpression = callResolver.resolveCallAndSelectCandidate(functionCall) + val withTransformedArguments = if (!resolvingAugmentedAssignment) { + dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments) + transformExplicitReceiver(functionCall).also { + it.replaceArgumentList(it.argumentList.transform(this, ResolutionMode.ContextDependent)) + dataFlowAnalyzer.exitCallArguments() + } + } else { + functionCall + } + val resultExpression = callResolver.resolveCallAndSelectCandidate(withTransformedArguments) val resultExplicitReceiver = resultExpression.explicitReceiver?.unwrapSmartcastExpression() if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccess) { // name.invoke() case @@ -395,7 +422,9 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT throw RuntimeException("While resolving call ${functionCall.render()}", e) } val result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data) - dataFlowAnalyzer.exitFunctionCall(result, callCompleted) + if (!resolvingAugmentedAssignment) { + dataFlowAnalyzer.exitFunctionCall(result, callCompleted) + } addReceiversFromExtensions(result) @@ -533,12 +562,12 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT require(operation != FirOperation.ASSIGN) assignmentOperatorStatement.transformAnnotations(transformer, ResolutionMode.ContextIndependent) - dataFlowAnalyzer.enterAugmentedAssignmentCall() + dataFlowAnalyzer.enterCallArguments(assignmentOperatorStatement, listOf(assignmentOperatorStatement.rightArgument)) val leftArgument = assignmentOperatorStatement.leftArgument.transformSingle(transformer, ResolutionMode.ContextIndependent) val rightArgument = assignmentOperatorStatement.rightArgument.transformSingle(transformer, ResolutionMode.ContextDependent) + dataFlowAnalyzer.exitCallArguments() val generator = GeneratorOfPlusAssignCalls(assignmentOperatorStatement, operation, leftArgument, rightArgument) - dataFlowAnalyzer.enterSelectAugmentedAssignmentCall() // x.plusAssign(y) val assignOperatorCall = generator.createAssignOperatorCall() @@ -556,8 +585,6 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT val operatorCallReference = resolvedOperatorCall.calleeReference as? FirNamedReferenceWithCandidate val operatorIsSuccessful = operatorCallReference?.isError == false - dataFlowAnalyzer.exitSelectAugmentedAssignmentCall() - fun operatorReturnTypeMatches(candidate: Candidate): Boolean { // After KT-45503, non-assign flavor of operator is checked more strictly: the return type must be assignable to the variable. val operatorCallReturnType = resolvedOperatorCall.typeRef.coneType @@ -671,11 +698,17 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT return equalityOperatorCall } + private var resolvingAugmentedAssignment: Boolean = false + private inline fun resolveCandidateForAssignmentOperatorCall(block: () -> T): T { - return callResolver.withNoArgumentsTransform { + assert(!resolvingAugmentedAssignment) + resolvingAugmentedAssignment = true + return try { context.withInferenceSession(InferenceSessionForAssignmentOperatorCall) { block() } + } finally { + resolvingAugmentedAssignment = false } } @@ -1121,12 +1154,12 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT }) } - dataFlowAnalyzer.enterDelegatedConstructorCall() - + dataFlowAnalyzer.enterCallArguments(delegatedConstructorCall, delegatedConstructorCall.arguments) val lastDispatchReceiver = implicitReceiverStack.lastDispatchReceiver() context.forDelegatedConstructorCall(containingConstructor, containingClass as? FirRegularClass, components) { delegatedConstructorCall.transformChildren(transformer, ResolutionMode.ContextDependent) } + dataFlowAnalyzer.exitCallArguments() val reference = delegatedConstructorCall.calleeReference val constructorType: ConeClassLikeType? = when (reference) { @@ -1225,15 +1258,14 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT augmentedArraySetCall.transformAnnotations(transformer, data) + dataFlowAnalyzer.enterCallArguments(augmentedArraySetCall, listOf(augmentedArraySetCall.rhs)) // transformedLhsCall: a.get(index) - dataFlowAnalyzer.enterAugmentedAssignmentCall() val transformedLhsCall = augmentedArraySetCall.lhsGetCall.transformSingle(transformer, ResolutionMode.ContextIndependent) val transformedRhs = augmentedArraySetCall.rhs.transformSingle(transformer, ResolutionMode.ContextDependent) + dataFlowAnalyzer.exitCallArguments() val generator = GeneratorOfPlusAssignCalls(augmentedArraySetCall, operation, transformedLhsCall, transformedRhs) - dataFlowAnalyzer.enterSelectAugmentedAssignmentCall() - // a.get(b).plusAssign(c) val assignOperatorCall = generator.createAssignOperatorCall() val resolvedAssignCall = resolveCandidateForAssignmentOperatorCall { @@ -1250,15 +1282,12 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT // prefer a "simpler" variant for dynamics if (transformedLhsCall.calleeReference.resolvedSymbol?.origin == FirDeclarationOrigin.DynamicScope) { - dataFlowAnalyzer.exitSelectAugmentedAssignmentCall() return chooseAssign() } // .set(, .get().plus(c)) val info = tryResolveAugmentedArraySetCallAsSetGetBlock(augmentedArraySetCall, transformedLhsCall, transformedRhs) - dataFlowAnalyzer.exitSelectAugmentedAssignmentCall() - val resolvedOperatorCall = info.operatorCall val operatorCallReference = resolvedOperatorCall.calleeReference as? FirNamedReferenceWithCandidate val operatorIsSuccessful = operatorCallReference?.isError == false @@ -1482,47 +1511,12 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT return anonymousObjectExpression } - private val nonLambdaArgumentTransformer = object : FirTransformer() { - override fun transformElement(element: E, data: ResolutionMode): E = - element.transform(this@FirExpressionsResolveTransformer, data) - - override fun transformAnonymousFunctionExpression( - anonymousFunctionExpression: FirAnonymousFunctionExpression, - data: ResolutionMode - ): FirStatement = anonymousFunctionExpression - } - - private val lambdaArgumentTransformer = object : FirTransformer() { - override fun transformElement(element: E, data: ResolutionMode): E = - element - - override fun transformAnonymousFunctionExpression( - anonymousFunctionExpression: FirAnonymousFunctionExpression, - data: ResolutionMode - ): FirStatement = this@FirExpressionsResolveTransformer.transformAnonymousFunctionExpression(anonymousFunctionExpression, data) - } - - override fun transformArgumentList(argumentList: FirArgumentList, data: ResolutionMode): FirArgumentList { - // Transform all normal arguments first and then lambda to make CFG correct. See KT-46825 - return argumentList - .transformArguments(nonLambdaArgumentTransformer, data) - .transformArguments(lambdaArgumentTransformer, data) - } - override fun transformAnonymousFunctionExpression( anonymousFunctionExpression: FirAnonymousFunctionExpression, data: ResolutionMode ): FirStatement { - anonymousFunctionExpression.transformAnonymousFunction(transformer, data) - when (data) { - is ResolutionMode.ContextDependent, is ResolutionMode.ContextDependentDelegate -> { - dataFlowAnalyzer.visitPostponedAnonymousFunction(anonymousFunctionExpression) - } - else -> { - dataFlowAnalyzer.exitAnonymousFunctionExpression(anonymousFunctionExpression) - } - } - return anonymousFunctionExpression + dataFlowAnalyzer.enterAnonymousFunctionExpression(anonymousFunctionExpression) + return anonymousFunctionExpression.transformAnonymousFunction(transformer, data) } // ------------------------------------------------------------------------------------------------ diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt index a0353299b4f..952d617d58d 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt @@ -243,9 +243,10 @@ class ExitDefaultArgumentsNode(owner: ControlFlowGraph, override val fir: FirVal // ----------------------------------- Anonymous function ----------------------------------- -class PostponedLambdaEnterNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNodeWithSubgraphs(owner, level, id) { +class SplitPostponedLambdasNode(owner: ControlFlowGraph, override val fir: FirStatement, val lambdas: List, level: Int, id: Int) + : CFGNodeWithSubgraphs(owner, level, id) { override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { - return visitor.visitPostponedLambdaEnterNode(this, data) + return visitor.visitSplitPostponedLambdasNode(this, data) } } @@ -261,9 +262,9 @@ class MergePostponedLambdaExitsNode(owner: ControlFlowGraph, override val fir: F } } -class AnonymousFunctionExpressionExitNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNode(owner, level, id) { +class AnonymousFunctionExpressionNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNodeWithSubgraphs(owner, level, id) { override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { - return visitor.visitAnonymousFunctionExpressionExitNode(this, data) + return visitor.visitAnonymousFunctionExpressionNode(this, data) } } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt index 43780d87685..c2b440a8fba 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt @@ -98,12 +98,10 @@ fun CFGNode<*>.render(): String = is WhenSubjectExpressionExitNode -> "Exit ${'$'}subj" - is PostponedLambdaEnterNode -> "Postponed enter to lambda" + is SplitPostponedLambdasNode -> "Postponed enter to lambda" is PostponedLambdaExitNode -> "Postponed exit from lambda" - - is AnonymousFunctionExpressionExitNode -> "Exit anonymous function expression" - is MergePostponedLambdaExitsNode -> "Merge postponed lambda exits" + is AnonymousFunctionExpressionNode -> "Exit anonymous function expression" is ClassEnterNode -> "Enter class ${owner.name}" is ClassExitNode -> "Exit class ${owner.name}" diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt index 054224b2708..9bb1af2fd6d 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt @@ -36,7 +36,7 @@ abstract class ControlFlowGraphVisitor { // ----------------------------------- Anonymous function ----------------------------------- - open fun visitPostponedLambdaEnterNode(node: PostponedLambdaEnterNode, data: D): R { + open fun visitSplitPostponedLambdasNode(node: SplitPostponedLambdasNode, data: D): R { return visitNode(node, data) } @@ -48,7 +48,7 @@ abstract class ControlFlowGraphVisitor { return visitNode(node, data) } - open fun visitAnonymousFunctionExpressionExitNode(node: AnonymousFunctionExpressionExitNode, data: D): R { + open fun visitAnonymousFunctionExpressionNode(node: AnonymousFunctionExpressionNode, data: D): R { return visitNode(node, data) } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt index 2247ef82b5b..f27ca0ecdf3 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt @@ -20,9 +20,13 @@ abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor