From 4367d6631f61e8738b6a9d5d560faf2c508bc44e Mon Sep 17 00:00:00 2001 From: Oleg Ivanov Date: Thu, 30 Jul 2020 17:13:11 +0300 Subject: [PATCH] [FIR] Add CallsInPlace contract analyzer --- .../boundSmartcastsInBranches.dot | 1517 +++++----- .../resolve/smartcasts/nullability.dot | 2590 +++++++++-------- .../bad/callsInPlace/inAnonymousObject.dot | 119 + .../bad/callsInPlace/inAnonymousObject.kt | 31 + .../bad/callsInPlace/inAnonymousObject.txt | 35 + .../bad/callsInPlace/inLocalClass.dot | 126 + .../bad/callsInPlace/inLocalClass.kt | 35 + .../bad/callsInPlace/inLocalClass.txt | 37 + .../bad/callsInPlace/inLocalFunction.dot | 47 + .../bad/callsInPlace/inLocalFunction.kt | 18 + .../bad/callsInPlace/inLocalFunction.txt | 16 + .../bad/callsInPlace/toLocalVariables.dot | 97 + .../bad/callsInPlace/toLocalVariables.kt | 26 + .../bad/callsInPlace/toLocalVariables.txt | 26 + .../good/callsInPlace/contractsUsage.dot | 131 + .../good/callsInPlace/contractsUsage.kt | 38 + .../good/callsInPlace/contractsUsage.txt | 42 + .../fromSource/good/callsInPlace/flow.dot | 274 ++ .../fromSource/good/callsInPlace/flow.kt | 45 + .../fromSource/good/callsInPlace/flow.txt | 56 + .../good/callsInPlace/inPlaceLambda.dot | 91 + .../good/callsInPlace/inPlaceLambda.kt | 26 + .../good/callsInPlace/inPlaceLambda.txt | 28 + .../fromSource/good/callsInPlace/simple.dot | 77 + .../fromSource/good/callsInPlace/simple.kt | 28 + .../fromSource/good/callsInPlace/simple.txt | 28 + .../initialization/fromLocalMembers.txt | 8 +- ...FirDiagnosticsWithStdlibTestGenerated.java | 66 + .../analysis/cfa/FirCallsEffectAnalyzer.kt | 310 ++ .../declaration/DefaultDeclarationCheckers.kt | 4 +- .../diagnostics/FirDefaultErrorMessages.kt | 70 +- .../fir/analysis/diagnostics/FirErrors.kt | 4 + .../description/EventOccurrencesRange.kt | 1 + .../tests/smartCasts/kt32358_2.fir.kt | 4 +- .../controlFlow/initialization/pos/5.fir.kt | 25 + .../controlFlow/initialization/pos/5.kt | 1 - .../controlFlow/unreachableCode/pos/7.fir.kt | 2 +- .../contractFunction/neg/1.fir.kt | 2 +- .../contractFunction/neg/4.fir.kt | 4 +- 39 files changed, 4021 insertions(+), 2064 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.txt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.dot create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.kt create mode 100644 compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.txt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt create mode 100644 compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/boundSmartcastsInBranches.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/boundSmartcastsInBranches.dot index f3be68dcb22..9e39d3e86d8 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/boundSmartcastsInBranches.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/boundSmartcastsInBranches.dot @@ -8,852 +8,859 @@ digraph boundSmartcastsInBranches_kt { 0 [label="Enter class A" style="filled" fillcolor=red]; subgraph cluster_1 { color=blue - 2 [label="Enter property" style="filled" fillcolor=red]; - 3 [label="Const: String()"]; - 4 [label="Exit property" style="filled" fillcolor=red]; + 1 [label="Part of class initialization"]; + 2 [label="Exit class A" style="filled" fillcolor=red]; } - 1 [label="Exit class A" style="filled" fillcolor=red]; - } - 0 -> {2} [color=green]; - 2 -> {3}; - 3 -> {4}; - 4 -> {1} [color=green]; + 0 -> {1} [color=green]; + 1 -> {2} [style=dotted]; + 1 -> {8} [color=green]; + 1 -> {8} [style=dashed]; - subgraph cluster_2 { - color=red - 5 [label="Enter function " style="filled" fillcolor=red]; - 6 [label="Delegated constructor call: super()"]; - 7 [label="Exit function " style="filled" fillcolor=red]; - } - 5 -> {6}; - 6 -> {7}; + subgraph cluster_2 { + color=red + 3 [label="Enter function " style="filled" fillcolor=red]; + 4 [label="Delegated constructor call: super()"]; + 5 [label="Exit function " style="filled" fillcolor=red]; + } + 3 -> {4}; + 4 -> {5}; - subgraph cluster_3 { - color=red - 8 [label="Enter function getter" style="filled" fillcolor=red]; - 9 [label="Exit function getter" style="filled" fillcolor=red]; - } - 8 -> {9}; + subgraph cluster_3 { + color=red + 6 [label="Enter function getter" style="filled" fillcolor=red]; + 7 [label="Exit function getter" style="filled" fillcolor=red]; + } + 6 -> {7}; + + subgraph cluster_4 { + color=red + 8 [label="Enter property" style="filled" fillcolor=red]; + 9 [label="Const: String()"]; + 10 [label="Exit property" style="filled" fillcolor=red]; + } + 8 -> {9}; + 9 -> {10}; + 10 -> {2} [color=green]; - subgraph cluster_4 { - color=red - 10 [label="Enter function test_0" style="filled" fillcolor=red]; subgraph cluster_5 { - color=blue - 11 [label="Enter block"]; - 12 [label="Const: Null(null)"]; - 13 [label="Variable declaration: lvar goodA: R|A?|"]; - 14 [label="Access variable R|/list|"]; - 15 [label="Function call: R|/list|.R|FakeOverride|>|()"]; - 16 [label="Variable declaration: lval : R|kotlin/collections/Iterator|"]; + color=red + 11 [label="Enter function test_0" style="filled" fillcolor=red]; subgraph cluster_6 { color=blue - 17 [label="Enter while loop"]; + 12 [label="Enter block"]; + 13 [label="Const: Null(null)"]; + 14 [label="Variable declaration: lvar goodA: R|A?|"]; + 15 [label="Access variable R|/list|"]; + 16 [label="Function call: R|/list|.R|FakeOverride|>|()"]; + 17 [label="Variable declaration: lval : R|kotlin/collections/Iterator|"]; subgraph cluster_7 { color=blue - 18 [label="Enter loop condition"]; - 19 [label="Access variable R|/|"]; - 20 [label="Function call: R|/|.R|kotlin/collections/Iterator.hasNext|()"]; - 21 [label="Exit loop condition"]; - } - subgraph cluster_8 { - color=blue - 22 [label="Enter loop block"]; + 18 [label="Enter while loop"]; + subgraph cluster_8 { + color=blue + 19 [label="Enter loop condition"]; + 20 [label="Access variable R|/|"]; + 21 [label="Function call: R|/|.R|kotlin/collections/Iterator.hasNext|()"]; + 22 [label="Exit loop condition"]; + } subgraph cluster_9 { color=blue - 23 [label="Enter block"]; - 24 [label="Access variable R|/|"]; - 25 [label="Function call: R|/|.R|FakeOverride|()"]; - 26 [label="Variable declaration: lval a: R|A|"]; + 23 [label="Enter loop block"]; subgraph cluster_10 { color=blue - 27 [label="Enter when"]; + 24 [label="Enter block"]; + 25 [label="Access variable R|/|"]; + 26 [label="Function call: R|/|.R|FakeOverride|()"]; + 27 [label="Variable declaration: lval a: R|A|"]; subgraph cluster_11 { color=blue - 28 [label="Enter when branch condition "]; - 29 [label="Access variable R|/goodA|"]; - 30 [label="Const: Null(null)"]; - 31 [label="Equality operator =="]; - 32 [label="Exit when branch condition"]; + 28 [label="Enter when"]; + subgraph cluster_12 { + color=blue + 29 [label="Enter when branch condition "]; + 30 [label="Access variable R|/goodA|"]; + 31 [label="Const: Null(null)"]; + 32 [label="Equality operator =="]; + 33 [label="Exit when branch condition"]; + } + 34 [label="Synthetic else branch"]; + 35 [label="Enter when branch result"]; + subgraph cluster_13 { + color=blue + 36 [label="Enter block"]; + 37 [label="Access variable R|/a|"]; + 38 [label="Assignment: R|/goodA|"]; + 39 [label="Jump: continue@@@[R|/|.R|kotlin/collections/Iterator.hasNext|()] "]; + 40 [label="Stub" style="filled" fillcolor=gray]; + 41 [label="Exit block" style="filled" fillcolor=gray]; + } + 42 [label="Exit when branch result" style="filled" fillcolor=gray]; + 43 [label="Exit when"]; } - 33 [label="Synthetic else branch"]; - 34 [label="Enter when branch result"]; - subgraph cluster_12 { - color=blue - 35 [label="Enter block"]; - 36 [label="Access variable R|/a|"]; - 37 [label="Assignment: R|/goodA|"]; - 38 [label="Jump: continue@@@[R|/|.R|kotlin/collections/Iterator.hasNext|()] "]; - 39 [label="Stub" style="filled" fillcolor=gray]; - 40 [label="Exit block" style="filled" fillcolor=gray]; - } - 41 [label="Exit when branch result" style="filled" fillcolor=gray]; - 42 [label="Exit when"]; + 44 [label="Access variable R|/goodA|"]; + 45 [label="Access variable R|/A.s|"]; + 46 [label="Exit block"]; } - 43 [label="Access variable R|/goodA|"]; - 44 [label="Access variable R|/A.s|"]; - 45 [label="Exit block"]; + 47 [label="Exit loop block"]; } - 46 [label="Exit loop block"]; + 48 [label="Exit whileloop"]; } - 47 [label="Exit whileloop"]; + 49 [label="Exit block"]; } - 48 [label="Exit block"]; + 50 [label="Exit function test_0" style="filled" fillcolor=red]; } - 49 [label="Exit function test_0" style="filled" fillcolor=red]; - } - 10 -> {11}; - 11 -> {12}; - 12 -> {13}; - 13 -> {14}; - 14 -> {15}; - 15 -> {16}; - 16 -> {17}; - 17 -> {18}; - 18 -> {19}; - 19 -> {20}; - 20 -> {21}; - 21 -> {47 22}; - 22 -> {23}; - 23 -> {24}; - 24 -> {25}; - 25 -> {26}; - 26 -> {27}; - 27 -> {28}; - 28 -> {29}; - 29 -> {30}; - 30 -> {31}; - 31 -> {32}; - 32 -> {34 33}; - 33 -> {42}; - 34 -> {35}; - 35 -> {36}; - 36 -> {37}; - 37 -> {38}; - 38 -> {39} [style=dotted]; - 38 -> {17} [color=green style=dashed]; - 39 -> {40} [style=dotted]; - 40 -> {41} [style=dotted]; - 41 -> {42} [style=dotted]; - 42 -> {43}; - 43 -> {44}; - 44 -> {45}; - 45 -> {46}; - 46 -> {18} [color=green style=dashed]; - 47 -> {48}; - 48 -> {49}; + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {48 23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {35 34}; + 34 -> {43}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40} [style=dotted]; + 39 -> {18} [color=green style=dashed]; + 40 -> {41} [style=dotted]; + 41 -> {42} [style=dotted]; + 42 -> {43} [style=dotted]; + 43 -> {44}; + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {19} [color=green style=dashed]; + 48 -> {49}; + 49 -> {50}; - subgraph cluster_13 { - color=red - 50 [label="Enter function test_1" style="filled" fillcolor=red]; subgraph cluster_14 { - color=blue - 51 [label="Enter block"]; - 52 [label="Variable declaration: lval x: R|kotlin/Any|"]; + color=red + 51 [label="Enter function test_1" style="filled" fillcolor=red]; subgraph cluster_15 { color=blue - 53 [label="Enter when"]; + 52 [label="Enter block"]; + 53 [label="Variable declaration: lval x: R|kotlin/Any|"]; subgraph cluster_16 { color=blue - 54 [label="Enter when branch condition "]; - 55 [label="Access variable R|/b|"]; - 56 [label="Exit when branch condition"]; + 54 [label="Enter when"]; + subgraph cluster_17 { + color=blue + 55 [label="Enter when branch condition "]; + 56 [label="Access variable R|/b|"]; + 57 [label="Exit when branch condition"]; + } + subgraph cluster_18 { + color=blue + 58 [label="Enter when branch condition else"]; + 59 [label="Exit when branch condition"]; + } + 60 [label="Enter when branch result"]; + subgraph cluster_19 { + color=blue + 61 [label="Enter block"]; + 62 [label="Access variable R|/a|"]; + 63 [label="Assignment: R|/x|"]; + 64 [label="Exit block"]; + } + 65 [label="Exit when branch result"]; + 66 [label="Enter when branch result"]; + subgraph cluster_20 { + color=blue + 67 [label="Enter block"]; + 68 [label="Function call: R|/A.A|()"]; + 69 [label="Assignment: R|/x|"]; + 70 [label="Exit block"]; + } + 71 [label="Exit when branch result"]; + 72 [label="Exit when"]; } - subgraph cluster_17 { - color=blue - 57 [label="Enter when branch condition else"]; - 58 [label="Exit when branch condition"]; - } - 59 [label="Enter when branch result"]; - subgraph cluster_18 { - color=blue - 60 [label="Enter block"]; - 61 [label="Access variable R|/a|"]; - 62 [label="Assignment: R|/x|"]; - 63 [label="Exit block"]; - } - 64 [label="Exit when branch result"]; - 65 [label="Enter when branch result"]; - subgraph cluster_19 { - color=blue - 66 [label="Enter block"]; - 67 [label="Function call: R|/A.A|()"]; - 68 [label="Assignment: R|/x|"]; - 69 [label="Exit block"]; - } - 70 [label="Exit when branch result"]; - 71 [label="Exit when"]; + 73 [label="Access variable R|/x|"]; + 74 [label="Access variable R|/A.s|"]; + 75 [label="Exit block"]; } - 72 [label="Access variable R|/x|"]; - 73 [label="Access variable R|/A.s|"]; - 74 [label="Exit block"]; + 76 [label="Exit function test_1" style="filled" fillcolor=red]; } - 75 [label="Exit function test_1" style="filled" fillcolor=red]; - } - 50 -> {51}; - 51 -> {52}; - 52 -> {53}; - 53 -> {54}; - 54 -> {55}; - 55 -> {56}; - 56 -> {65 57}; - 57 -> {58}; - 58 -> {59}; - 59 -> {60}; - 60 -> {61}; - 61 -> {62}; - 62 -> {63}; - 63 -> {64}; - 64 -> {71}; - 65 -> {66}; - 66 -> {67}; - 67 -> {68}; - 68 -> {69}; - 69 -> {70}; - 70 -> {71}; - 71 -> {72}; - 72 -> {73}; - 73 -> {74}; - 74 -> {75}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {66 58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {72}; + 66 -> {67}; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; - subgraph cluster_20 { - color=red - 76 [label="Enter function test_2" style="filled" fillcolor=red]; subgraph cluster_21 { - color=blue - 77 [label="Enter block"]; - 78 [label="Variable declaration: lval x: R|kotlin/Any|"]; + color=red + 77 [label="Enter function test_2" style="filled" fillcolor=red]; subgraph cluster_22 { color=blue - 79 [label="Enter when"]; + 78 [label="Enter block"]; + 79 [label="Variable declaration: lval x: R|kotlin/Any|"]; subgraph cluster_23 { color=blue - 80 [label="Enter when branch condition "]; - 81 [label="Access variable R|/b|"]; - 82 [label="Exit when branch condition"]; + 80 [label="Enter when"]; + subgraph cluster_24 { + color=blue + 81 [label="Enter when branch condition "]; + 82 [label="Access variable R|/b|"]; + 83 [label="Exit when branch condition"]; + } + subgraph cluster_25 { + color=blue + 84 [label="Enter when branch condition else"]; + 85 [label="Exit when branch condition"]; + } + 86 [label="Enter when branch result"]; + subgraph cluster_26 { + color=blue + 87 [label="Enter block"]; + 88 [label="Access variable R|/a|"]; + 89 [label="Assignment: R|/x|"]; + 90 [label="Access variable R|/a|"]; + 91 [label="Type operator: (R|/a| as R|A|)"]; + 92 [label="Exit block"]; + } + 93 [label="Exit when branch result"]; + 94 [label="Enter when branch result"]; + subgraph cluster_27 { + color=blue + 95 [label="Enter block"]; + 96 [label="Function call: R|/A.A|()"]; + 97 [label="Assignment: R|/x|"]; + 98 [label="Exit block"]; + } + 99 [label="Exit when branch result"]; + 100 [label="Exit when"]; } - subgraph cluster_24 { - color=blue - 83 [label="Enter when branch condition else"]; - 84 [label="Exit when branch condition"]; - } - 85 [label="Enter when branch result"]; - subgraph cluster_25 { - color=blue - 86 [label="Enter block"]; - 87 [label="Access variable R|/a|"]; - 88 [label="Assignment: R|/x|"]; - 89 [label="Access variable R|/a|"]; - 90 [label="Type operator: (R|/a| as R|A|)"]; - 91 [label="Exit block"]; - } - 92 [label="Exit when branch result"]; - 93 [label="Enter when branch result"]; - subgraph cluster_26 { - color=blue - 94 [label="Enter block"]; - 95 [label="Function call: R|/A.A|()"]; - 96 [label="Assignment: R|/x|"]; - 97 [label="Exit block"]; - } - 98 [label="Exit when branch result"]; - 99 [label="Exit when"]; + 101 [label="Access variable R|/x|"]; + 102 [label="Access variable R|/A.s|"]; + 103 [label="Exit block"]; } - 100 [label="Access variable R|/x|"]; - 101 [label="Access variable R|/A.s|"]; - 102 [label="Exit block"]; + 104 [label="Exit function test_2" style="filled" fillcolor=red]; } - 103 [label="Exit function test_2" style="filled" fillcolor=red]; - } - 76 -> {77}; - 77 -> {78}; - 78 -> {79}; - 79 -> {80}; - 80 -> {81}; - 81 -> {82}; - 82 -> {93 83}; - 83 -> {84}; - 84 -> {85}; - 85 -> {86}; - 86 -> {87}; - 87 -> {88}; - 88 -> {89}; - 89 -> {90}; - 90 -> {91}; - 91 -> {92}; - 92 -> {99}; - 93 -> {94}; - 94 -> {95}; - 95 -> {96}; - 96 -> {97}; - 97 -> {98}; - 98 -> {99}; - 99 -> {100}; - 100 -> {101}; - 101 -> {102}; - 102 -> {103}; + 77 -> {78}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {94 84}; + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {100}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {100}; + 100 -> {101}; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; - subgraph cluster_27 { - color=red - 104 [label="Enter function test_3" style="filled" fillcolor=red]; subgraph cluster_28 { - color=blue - 105 [label="Enter block"]; - 106 [label="Variable declaration: lval x: R|kotlin/Any|"]; + color=red + 105 [label="Enter function test_3" style="filled" fillcolor=red]; subgraph cluster_29 { color=blue - 107 [label="Enter when"]; + 106 [label="Enter block"]; + 107 [label="Variable declaration: lval x: R|kotlin/Any|"]; subgraph cluster_30 { color=blue - 108 [label="Enter when branch condition "]; - 109 [label="Access variable R|/b|"]; - 110 [label="Exit when branch condition"]; + 108 [label="Enter when"]; + subgraph cluster_31 { + color=blue + 109 [label="Enter when branch condition "]; + 110 [label="Access variable R|/b|"]; + 111 [label="Exit when branch condition"]; + } + subgraph cluster_32 { + color=blue + 112 [label="Enter when branch condition else"]; + 113 [label="Exit when branch condition"]; + } + 114 [label="Enter when branch result"]; + subgraph cluster_33 { + color=blue + 115 [label="Enter block"]; + 116 [label="Access variable R|/a|"]; + 117 [label="Type operator: (R|/a| as R|A|)"]; + 118 [label="Access variable R|/a|"]; + 119 [label="Assignment: R|/x|"]; + 120 [label="Exit block"]; + } + 121 [label="Exit when branch result"]; + 122 [label="Enter when branch result"]; + subgraph cluster_34 { + color=blue + 123 [label="Enter block"]; + 124 [label="Function call: R|/A.A|()"]; + 125 [label="Assignment: R|/x|"]; + 126 [label="Exit block"]; + } + 127 [label="Exit when branch result"]; + 128 [label="Exit when"]; } - subgraph cluster_31 { - color=blue - 111 [label="Enter when branch condition else"]; - 112 [label="Exit when branch condition"]; - } - 113 [label="Enter when branch result"]; - subgraph cluster_32 { - color=blue - 114 [label="Enter block"]; - 115 [label="Access variable R|/a|"]; - 116 [label="Type operator: (R|/a| as R|A|)"]; - 117 [label="Access variable R|/a|"]; - 118 [label="Assignment: R|/x|"]; - 119 [label="Exit block"]; - } - 120 [label="Exit when branch result"]; - 121 [label="Enter when branch result"]; - subgraph cluster_33 { - color=blue - 122 [label="Enter block"]; - 123 [label="Function call: R|/A.A|()"]; - 124 [label="Assignment: R|/x|"]; - 125 [label="Exit block"]; - } - 126 [label="Exit when branch result"]; - 127 [label="Exit when"]; + 129 [label="Access variable R|/x|"]; + 130 [label="Access variable R|/A.s|"]; + 131 [label="Exit block"]; } - 128 [label="Access variable R|/x|"]; - 129 [label="Access variable R|/A.s|"]; - 130 [label="Exit block"]; + 132 [label="Exit function test_3" style="filled" fillcolor=red]; } - 131 [label="Exit function test_3" style="filled" fillcolor=red]; - } - 104 -> {105}; - 105 -> {106}; - 106 -> {107}; - 107 -> {108}; - 108 -> {109}; - 109 -> {110}; - 110 -> {121 111}; - 111 -> {112}; - 112 -> {113}; - 113 -> {114}; - 114 -> {115}; - 115 -> {116}; - 116 -> {117}; - 117 -> {118}; - 118 -> {119}; - 119 -> {120}; - 120 -> {127}; - 121 -> {122}; - 122 -> {123}; - 123 -> {124}; - 124 -> {125}; - 125 -> {126}; - 126 -> {127}; - 127 -> {128}; - 128 -> {129}; - 129 -> {130}; - 130 -> {131}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {110}; + 110 -> {111}; + 111 -> {122 112}; + 112 -> {113}; + 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {128}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; + 128 -> {129}; + 129 -> {130}; + 130 -> {131}; + 131 -> {132}; - subgraph cluster_34 { - color=red - 132 [label="Enter function test_4" style="filled" fillcolor=red]; subgraph cluster_35 { - color=blue - 133 [label="Enter block"]; - 134 [label="Variable declaration: lval x: R|kotlin/Any|"]; + color=red + 133 [label="Enter function test_4" style="filled" fillcolor=red]; subgraph cluster_36 { color=blue - 135 [label="Enter when"]; + 134 [label="Enter block"]; + 135 [label="Variable declaration: lval x: R|kotlin/Any|"]; subgraph cluster_37 { color=blue - 136 [label="Enter when branch condition "]; - 137 [label="Access variable R|/b|"]; - 138 [label="Exit when branch condition"]; + 136 [label="Enter when"]; + subgraph cluster_38 { + color=blue + 137 [label="Enter when branch condition "]; + 138 [label="Access variable R|/b|"]; + 139 [label="Exit when branch condition"]; + } + subgraph cluster_39 { + color=blue + 140 [label="Enter when branch condition else"]; + 141 [label="Exit when branch condition"]; + } + 142 [label="Enter when branch result"]; + subgraph cluster_40 { + color=blue + 143 [label="Enter block"]; + 144 [label="Access variable R|/a|"]; + 145 [label="Assignment: R|/x|"]; + 146 [label="Exit block"]; + } + 147 [label="Exit when branch result"]; + 148 [label="Enter when branch result"]; + subgraph cluster_41 { + color=blue + 149 [label="Enter block"]; + 150 [label="Access variable R|/a|"]; + 151 [label="Assignment: R|/x|"]; + 152 [label="Exit block"]; + } + 153 [label="Exit when branch result"]; + 154 [label="Exit when"]; } - subgraph cluster_38 { - color=blue - 139 [label="Enter when branch condition else"]; - 140 [label="Exit when branch condition"]; - } - 141 [label="Enter when branch result"]; - subgraph cluster_39 { - color=blue - 142 [label="Enter block"]; - 143 [label="Access variable R|/a|"]; - 144 [label="Assignment: R|/x|"]; - 145 [label="Exit block"]; - } - 146 [label="Exit when branch result"]; - 147 [label="Enter when branch result"]; - subgraph cluster_40 { - color=blue - 148 [label="Enter block"]; - 149 [label="Access variable R|/a|"]; - 150 [label="Assignment: R|/x|"]; - 151 [label="Exit block"]; - } - 152 [label="Exit when branch result"]; - 153 [label="Exit when"]; + 155 [label="Access variable R|/x|"]; + 156 [label="Type operator: (R|/x| as R|A|)"]; + 157 [label="Access variable R|/x|"]; + 158 [label="Access variable R|/A.s|"]; + 159 [label="Access variable R|/a|"]; + 160 [label="Access variable R|/A.s|"]; + 161 [label="Exit block"]; } - 154 [label="Access variable R|/x|"]; - 155 [label="Type operator: (R|/x| as R|A|)"]; - 156 [label="Access variable R|/x|"]; - 157 [label="Access variable R|/A.s|"]; - 158 [label="Access variable R|/a|"]; - 159 [label="Access variable R|/A.s|"]; - 160 [label="Exit block"]; + 162 [label="Exit function test_4" style="filled" fillcolor=red]; } - 161 [label="Exit function test_4" style="filled" fillcolor=red]; - } - 132 -> {133}; - 133 -> {134}; - 134 -> {135}; - 135 -> {136}; - 136 -> {137}; - 137 -> {138}; - 138 -> {147 139}; - 139 -> {140}; - 140 -> {141}; - 141 -> {142}; - 142 -> {143}; - 143 -> {144}; - 144 -> {145}; - 145 -> {146}; - 146 -> {153}; - 147 -> {148}; - 148 -> {149}; - 149 -> {150}; - 150 -> {151}; - 151 -> {152}; - 152 -> {153}; - 153 -> {154}; - 154 -> {155}; - 155 -> {156}; - 156 -> {157}; - 157 -> {158}; - 158 -> {159}; - 159 -> {160}; - 160 -> {161}; + 133 -> {134}; + 134 -> {135}; + 135 -> {136}; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; + 139 -> {148 140}; + 140 -> {141}; + 141 -> {142}; + 142 -> {143}; + 143 -> {144}; + 144 -> {145}; + 145 -> {146}; + 146 -> {147}; + 147 -> {154}; + 148 -> {149}; + 149 -> {150}; + 150 -> {151}; + 151 -> {152}; + 152 -> {153}; + 153 -> {154}; + 154 -> {155}; + 155 -> {156}; + 156 -> {157}; + 157 -> {158}; + 158 -> {159}; + 159 -> {160}; + 160 -> {161}; + 161 -> {162}; - subgraph cluster_41 { - color=red - 162 [label="Enter function test_5" style="filled" fillcolor=red]; subgraph cluster_42 { - color=blue - 163 [label="Enter block"]; - 164 [label="Variable declaration: lval x: R|kotlin/Any|"]; + color=red + 163 [label="Enter function test_5" style="filled" fillcolor=red]; subgraph cluster_43 { color=blue - 165 [label="Enter when"]; + 164 [label="Enter block"]; + 165 [label="Variable declaration: lval x: R|kotlin/Any|"]; subgraph cluster_44 { color=blue - 166 [label="Enter when branch condition "]; - 167 [label="Access variable R|/b|"]; - 168 [label="Exit when branch condition"]; + 166 [label="Enter when"]; + subgraph cluster_45 { + color=blue + 167 [label="Enter when branch condition "]; + 168 [label="Access variable R|/b|"]; + 169 [label="Exit when branch condition"]; + } + subgraph cluster_46 { + color=blue + 170 [label="Enter when branch condition else"]; + 171 [label="Exit when branch condition"]; + } + 172 [label="Enter when branch result"]; + subgraph cluster_47 { + color=blue + 173 [label="Enter block"]; + 174 [label="Access variable R|/a|"]; + 175 [label="Assignment: R|/x|"]; + 176 [label="Exit block"]; + } + 177 [label="Exit when branch result"]; + 178 [label="Enter when branch result"]; + subgraph cluster_48 { + color=blue + 179 [label="Enter block"]; + 180 [label="Access variable R|/a|"]; + 181 [label="Assignment: R|/x|"]; + 182 [label="Exit block"]; + } + 183 [label="Exit when branch result"]; + 184 [label="Exit when"]; } - subgraph cluster_45 { - color=blue - 169 [label="Enter when branch condition else"]; - 170 [label="Exit when branch condition"]; - } - 171 [label="Enter when branch result"]; - subgraph cluster_46 { - color=blue - 172 [label="Enter block"]; - 173 [label="Access variable R|/a|"]; - 174 [label="Assignment: R|/x|"]; - 175 [label="Exit block"]; - } - 176 [label="Exit when branch result"]; - 177 [label="Enter when branch result"]; - subgraph cluster_47 { - color=blue - 178 [label="Enter block"]; - 179 [label="Access variable R|/a|"]; - 180 [label="Assignment: R|/x|"]; - 181 [label="Exit block"]; - } - 182 [label="Exit when branch result"]; - 183 [label="Exit when"]; + 185 [label="Access variable R|/a|"]; + 186 [label="Type operator: (R|/a| as R|A|)"]; + 187 [label="Access variable R|/x|"]; + 188 [label="Access variable R|/A.s|"]; + 189 [label="Access variable R|/a|"]; + 190 [label="Access variable R|/A.s|"]; + 191 [label="Exit block"]; } - 184 [label="Access variable R|/a|"]; - 185 [label="Type operator: (R|/a| as R|A|)"]; - 186 [label="Access variable R|/x|"]; - 187 [label="Access variable R|/A.s|"]; - 188 [label="Access variable R|/a|"]; - 189 [label="Access variable R|/A.s|"]; - 190 [label="Exit block"]; + 192 [label="Exit function test_5" style="filled" fillcolor=red]; } - 191 [label="Exit function test_5" style="filled" fillcolor=red]; - } - 162 -> {163}; - 163 -> {164}; - 164 -> {165}; - 165 -> {166}; - 166 -> {167}; - 167 -> {168}; - 168 -> {177 169}; - 169 -> {170}; - 170 -> {171}; - 171 -> {172}; - 172 -> {173}; - 173 -> {174}; - 174 -> {175}; - 175 -> {176}; - 176 -> {183}; - 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}; + 163 -> {164}; + 164 -> {165}; + 165 -> {166}; + 166 -> {167}; + 167 -> {168}; + 168 -> {169}; + 169 -> {178 170}; + 170 -> {171}; + 171 -> {172}; + 172 -> {173}; + 173 -> {174}; + 174 -> {175}; + 175 -> {176}; + 176 -> {177}; + 177 -> {184}; + 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}; - subgraph cluster_48 { - color=red - 192 [label="Enter function test_6" style="filled" fillcolor=red]; subgraph cluster_49 { - color=blue - 193 [label="Enter block"]; - 194 [label="Variable declaration: lval x: R|kotlin/Any|"]; - 195 [label="Access variable R|/a|"]; - 196 [label="Assignment: R|/x|"]; - 197 [label="Access variable R|/x|"]; - 198 [label="Access variable R|/A.s|"]; - 199 [label="Exit block"]; + color=red + 193 [label="Enter function test_6" style="filled" fillcolor=red]; + subgraph cluster_50 { + color=blue + 194 [label="Enter block"]; + 195 [label="Variable declaration: lval x: R|kotlin/Any|"]; + 196 [label="Access variable R|/a|"]; + 197 [label="Assignment: R|/x|"]; + 198 [label="Access variable R|/x|"]; + 199 [label="Access variable R|/A.s|"]; + 200 [label="Exit block"]; + } + 201 [label="Exit function test_6" style="filled" fillcolor=red]; } - 200 [label="Exit function test_6" style="filled" fillcolor=red]; - } - 192 -> {193}; - 193 -> {194}; - 194 -> {195}; - 195 -> {196}; - 196 -> {197}; - 197 -> {198}; - 198 -> {199}; - 199 -> {200}; + 193 -> {194}; + 194 -> {195}; + 195 -> {196}; + 196 -> {197}; + 197 -> {198}; + 198 -> {199}; + 199 -> {200}; + 200 -> {201}; - subgraph cluster_50 { - color=red - 201 [label="Enter function test_7" style="filled" fillcolor=red]; subgraph cluster_51 { - color=blue - 202 [label="Enter block"]; - 203 [label="Const: Null(null)"]; - 204 [label="Variable declaration: lval z: R|kotlin/String?|"]; - 205 [label="Access variable R|/z|"]; - 206 [label="Variable declaration: lvar y: R|kotlin/String?|"]; - 207 [label="Access variable R|/y|"]; - 208 [label="Variable declaration: lval x: R|kotlin/String?|"]; + color=red + 202 [label="Enter function test_7" style="filled" fillcolor=red]; subgraph cluster_52 { color=blue - 209 [label="Enter when"]; + 203 [label="Enter block"]; + 204 [label="Const: Null(null)"]; + 205 [label="Variable declaration: lval z: R|kotlin/String?|"]; + 206 [label="Access variable R|/z|"]; + 207 [label="Variable declaration: lvar y: R|kotlin/String?|"]; + 208 [label="Access variable R|/y|"]; + 209 [label="Variable declaration: lval x: R|kotlin/String?|"]; subgraph cluster_53 { color=blue - 210 [label="Enter when branch condition "]; - 211 [label="Access variable R|/x|"]; - 212 [label="Const: Null(null)"]; - 213 [label="Equality operator !="]; - 214 [label="Exit when branch condition"]; + 210 [label="Enter when"]; + subgraph cluster_54 { + color=blue + 211 [label="Enter when branch condition "]; + 212 [label="Access variable R|/x|"]; + 213 [label="Const: Null(null)"]; + 214 [label="Equality operator !="]; + 215 [label="Exit when branch condition"]; + } + 216 [label="Synthetic else branch"]; + 217 [label="Enter when branch result"]; + subgraph cluster_55 { + color=blue + 218 [label="Enter block"]; + 219 [label="Access variable R|/x|"]; + 220 [label="Access variable R|kotlin/String.length|"]; + 221 [label="Access variable R|/y|"]; + 222 [label="Access variable R|kotlin/String.length|"]; + 223 [label="Access variable R|/z|"]; + 224 [label="Access variable R|kotlin/String.length|"]; + 225 [label="Exit block"]; + } + 226 [label="Exit when branch result"]; + 227 [label="Exit when"]; } - 215 [label="Synthetic else branch"]; - 216 [label="Enter when branch result"]; - subgraph cluster_54 { - color=blue - 217 [label="Enter block"]; - 218 [label="Access variable R|/x|"]; - 219 [label="Access variable R|kotlin/String.length|"]; - 220 [label="Access variable R|/y|"]; - 221 [label="Access variable R|kotlin/String.length|"]; - 222 [label="Access variable R|/z|"]; - 223 [label="Access variable R|kotlin/String.length|"]; - 224 [label="Exit block"]; - } - 225 [label="Exit when branch result"]; - 226 [label="Exit when"]; - } - subgraph cluster_55 { - color=blue - 227 [label="Enter when"]; subgraph cluster_56 { color=blue - 228 [label="Enter when branch condition "]; - 229 [label="Access variable R|/y|"]; - 230 [label="Const: Null(null)"]; - 231 [label="Equality operator !="]; - 232 [label="Exit when branch condition"]; + 228 [label="Enter when"]; + subgraph cluster_57 { + color=blue + 229 [label="Enter when branch condition "]; + 230 [label="Access variable R|/y|"]; + 231 [label="Const: Null(null)"]; + 232 [label="Equality operator !="]; + 233 [label="Exit when branch condition"]; + } + 234 [label="Synthetic else branch"]; + 235 [label="Enter when branch result"]; + subgraph cluster_58 { + color=blue + 236 [label="Enter block"]; + 237 [label="Access variable R|/x|"]; + 238 [label="Access variable R|kotlin/String.length|"]; + 239 [label="Access variable R|/y|"]; + 240 [label="Access variable R|kotlin/String.length|"]; + 241 [label="Access variable R|/z|"]; + 242 [label="Access variable R|kotlin/String.length|"]; + 243 [label="Exit block"]; + } + 244 [label="Exit when branch result"]; + 245 [label="Exit when"]; } - 233 [label="Synthetic else branch"]; - 234 [label="Enter when branch result"]; - subgraph cluster_57 { - color=blue - 235 [label="Enter block"]; - 236 [label="Access variable R|/x|"]; - 237 [label="Access variable R|kotlin/String.length|"]; - 238 [label="Access variable R|/y|"]; - 239 [label="Access variable R|kotlin/String.length|"]; - 240 [label="Access variable R|/z|"]; - 241 [label="Access variable R|kotlin/String.length|"]; - 242 [label="Exit block"]; - } - 243 [label="Exit when branch result"]; - 244 [label="Exit when"]; - } - subgraph cluster_58 { - color=blue - 245 [label="Enter when"]; subgraph cluster_59 { color=blue - 246 [label="Enter when branch condition "]; - 247 [label="Access variable R|/z|"]; - 248 [label="Const: Null(null)"]; - 249 [label="Equality operator !="]; - 250 [label="Exit when branch condition"]; + 246 [label="Enter when"]; + subgraph cluster_60 { + color=blue + 247 [label="Enter when branch condition "]; + 248 [label="Access variable R|/z|"]; + 249 [label="Const: Null(null)"]; + 250 [label="Equality operator !="]; + 251 [label="Exit when branch condition"]; + } + 252 [label="Synthetic else branch"]; + 253 [label="Enter when branch result"]; + subgraph cluster_61 { + color=blue + 254 [label="Enter block"]; + 255 [label="Access variable R|/x|"]; + 256 [label="Access variable R|kotlin/String.length|"]; + 257 [label="Access variable R|/y|"]; + 258 [label="Access variable R|kotlin/String.length|"]; + 259 [label="Access variable R|/z|"]; + 260 [label="Access variable R|kotlin/String.length|"]; + 261 [label="Exit block"]; + } + 262 [label="Exit when branch result"]; + 263 [label="Exit when"]; } - 251 [label="Synthetic else branch"]; - 252 [label="Enter when branch result"]; - subgraph cluster_60 { - color=blue - 253 [label="Enter block"]; - 254 [label="Access variable R|/x|"]; - 255 [label="Access variable R|kotlin/String.length|"]; - 256 [label="Access variable R|/y|"]; - 257 [label="Access variable R|kotlin/String.length|"]; - 258 [label="Access variable R|/z|"]; - 259 [label="Access variable R|kotlin/String.length|"]; - 260 [label="Exit block"]; - } - 261 [label="Exit when branch result"]; - 262 [label="Exit when"]; - } - 263 [label="Const: Null(null)"]; - 264 [label="Assignment: R|/y|"]; - subgraph cluster_61 { - color=blue - 265 [label="Enter when"]; + 264 [label="Const: Null(null)"]; + 265 [label="Assignment: R|/y|"]; subgraph cluster_62 { color=blue - 266 [label="Enter when branch condition "]; - 267 [label="Access variable R|/x|"]; - 268 [label="Const: Null(null)"]; - 269 [label="Equality operator !="]; - 270 [label="Exit when branch condition"]; + 266 [label="Enter when"]; + subgraph cluster_63 { + color=blue + 267 [label="Enter when branch condition "]; + 268 [label="Access variable R|/x|"]; + 269 [label="Const: Null(null)"]; + 270 [label="Equality operator !="]; + 271 [label="Exit when branch condition"]; + } + 272 [label="Synthetic else branch"]; + 273 [label="Enter when branch result"]; + subgraph cluster_64 { + color=blue + 274 [label="Enter block"]; + 275 [label="Access variable R|/x|"]; + 276 [label="Access variable R|kotlin/String.length|"]; + 277 [label="Access variable R|/y|"]; + 278 [label="Access variable #"]; + 279 [label="Access variable R|/z|"]; + 280 [label="Access variable R|kotlin/String.length|"]; + 281 [label="Exit block"]; + } + 282 [label="Exit when branch result"]; + 283 [label="Exit when"]; } - 271 [label="Synthetic else branch"]; - 272 [label="Enter when branch result"]; - subgraph cluster_63 { - color=blue - 273 [label="Enter block"]; - 274 [label="Access variable R|/x|"]; - 275 [label="Access variable R|kotlin/String.length|"]; - 276 [label="Access variable R|/y|"]; - 277 [label="Access variable #"]; - 278 [label="Access variable R|/z|"]; - 279 [label="Access variable R|kotlin/String.length|"]; - 280 [label="Exit block"]; - } - 281 [label="Exit when branch result"]; - 282 [label="Exit when"]; - } - subgraph cluster_64 { - color=blue - 283 [label="Enter when"]; subgraph cluster_65 { color=blue - 284 [label="Enter when branch condition "]; - 285 [label="Access variable R|/y|"]; - 286 [label="Const: Null(null)"]; - 287 [label="Equality operator !="]; - 288 [label="Exit when branch condition"]; + 284 [label="Enter when"]; + subgraph cluster_66 { + color=blue + 285 [label="Enter when branch condition "]; + 286 [label="Access variable R|/y|"]; + 287 [label="Const: Null(null)"]; + 288 [label="Equality operator !="]; + 289 [label="Exit when branch condition"]; + } + 290 [label="Synthetic else branch"]; + 291 [label="Enter when branch result"]; + subgraph cluster_67 { + color=blue + 292 [label="Enter block"]; + 293 [label="Access variable R|/x|"]; + 294 [label="Access variable #"]; + 295 [label="Access variable R|/y|"]; + 296 [label="Access variable R|kotlin/String.length|"]; + 297 [label="Access variable R|/z|"]; + 298 [label="Access variable #"]; + 299 [label="Exit block"]; + } + 300 [label="Exit when branch result"]; + 301 [label="Exit when"]; } - 289 [label="Synthetic else branch"]; - 290 [label="Enter when branch result"]; - subgraph cluster_66 { - color=blue - 291 [label="Enter block"]; - 292 [label="Access variable R|/x|"]; - 293 [label="Access variable #"]; - 294 [label="Access variable R|/y|"]; - 295 [label="Access variable R|kotlin/String.length|"]; - 296 [label="Access variable R|/z|"]; - 297 [label="Access variable #"]; - 298 [label="Exit block"]; - } - 299 [label="Exit when branch result"]; - 300 [label="Exit when"]; - } - subgraph cluster_67 { - color=blue - 301 [label="Enter when"]; subgraph cluster_68 { color=blue - 302 [label="Enter when branch condition "]; - 303 [label="Access variable R|/z|"]; - 304 [label="Const: Null(null)"]; - 305 [label="Equality operator !="]; - 306 [label="Exit when branch condition"]; + 302 [label="Enter when"]; + subgraph cluster_69 { + color=blue + 303 [label="Enter when branch condition "]; + 304 [label="Access variable R|/z|"]; + 305 [label="Const: Null(null)"]; + 306 [label="Equality operator !="]; + 307 [label="Exit when branch condition"]; + } + 308 [label="Synthetic else branch"]; + 309 [label="Enter when branch result"]; + subgraph cluster_70 { + color=blue + 310 [label="Enter block"]; + 311 [label="Access variable R|/x|"]; + 312 [label="Access variable R|kotlin/String.length|"]; + 313 [label="Access variable R|/y|"]; + 314 [label="Access variable #"]; + 315 [label="Access variable R|/z|"]; + 316 [label="Access variable R|kotlin/String.length|"]; + 317 [label="Exit block"]; + } + 318 [label="Exit when branch result"]; + 319 [label="Exit when"]; } - 307 [label="Synthetic else branch"]; - 308 [label="Enter when branch result"]; - subgraph cluster_69 { - color=blue - 309 [label="Enter block"]; - 310 [label="Access variable R|/x|"]; - 311 [label="Access variable R|kotlin/String.length|"]; - 312 [label="Access variable R|/y|"]; - 313 [label="Access variable #"]; - 314 [label="Access variable R|/z|"]; - 315 [label="Access variable R|kotlin/String.length|"]; - 316 [label="Exit block"]; - } - 317 [label="Exit when branch result"]; - 318 [label="Exit when"]; + 320 [label="Exit block"]; } - 319 [label="Exit block"]; + 321 [label="Exit function test_7" style="filled" fillcolor=red]; } - 320 [label="Exit function test_7" style="filled" fillcolor=red]; - } - 201 -> {202}; - 202 -> {203}; - 203 -> {204}; - 204 -> {205}; - 205 -> {206}; - 206 -> {207}; - 207 -> {208}; - 208 -> {209}; - 209 -> {210}; - 210 -> {211}; - 211 -> {212}; - 212 -> {213}; - 213 -> {214}; - 214 -> {216 215}; - 215 -> {226}; - 216 -> {217}; - 217 -> {218}; - 218 -> {219}; - 219 -> {220}; - 220 -> {221}; - 221 -> {222}; - 222 -> {223}; - 223 -> {224}; - 224 -> {225}; - 225 -> {226}; - 226 -> {227}; - 227 -> {228}; - 228 -> {229}; - 229 -> {230}; - 230 -> {231}; - 231 -> {232}; - 232 -> {234 233}; - 233 -> {244}; - 234 -> {235}; - 235 -> {236}; - 236 -> {237}; - 237 -> {238}; - 238 -> {239}; - 239 -> {240}; - 240 -> {241}; - 241 -> {242}; - 242 -> {243}; - 243 -> {244}; - 244 -> {245}; - 245 -> {246}; - 246 -> {247}; - 247 -> {248}; - 248 -> {249}; - 249 -> {250}; - 250 -> {252 251}; - 251 -> {262}; - 252 -> {253}; - 253 -> {254}; - 254 -> {255}; - 255 -> {256}; - 256 -> {257}; - 257 -> {258}; - 258 -> {259}; - 259 -> {260}; - 260 -> {261}; - 261 -> {262}; - 262 -> {263}; - 263 -> {264}; - 264 -> {265}; - 265 -> {266}; - 266 -> {267}; - 267 -> {268}; - 268 -> {269}; - 269 -> {270}; - 270 -> {272 271}; - 271 -> {282}; - 272 -> {273}; - 273 -> {274}; - 274 -> {275}; - 275 -> {276}; - 276 -> {277}; - 277 -> {278}; - 278 -> {279}; - 279 -> {280}; - 280 -> {281}; - 281 -> {282}; - 282 -> {283}; - 283 -> {284}; - 284 -> {285}; - 285 -> {286}; - 286 -> {287}; - 287 -> {288}; - 288 -> {290 289}; - 289 -> {300}; - 290 -> {291}; - 291 -> {292}; - 292 -> {293}; - 293 -> {294}; - 294 -> {295}; - 295 -> {296}; - 296 -> {297}; - 297 -> {298}; - 298 -> {299}; - 299 -> {300}; - 300 -> {301}; - 301 -> {302}; - 302 -> {303}; - 303 -> {304}; - 304 -> {305}; - 305 -> {306}; - 306 -> {308 307}; - 307 -> {318}; - 308 -> {309}; - 309 -> {310}; - 310 -> {311}; - 311 -> {312}; - 312 -> {313}; - 313 -> {314}; - 314 -> {315}; - 315 -> {316}; - 316 -> {317}; - 317 -> {318}; - 318 -> {319}; - 319 -> {320}; + 202 -> {203}; + 203 -> {204}; + 204 -> {205}; + 205 -> {206}; + 206 -> {207}; + 207 -> {208}; + 208 -> {209}; + 209 -> {210}; + 210 -> {211}; + 211 -> {212}; + 212 -> {213}; + 213 -> {214}; + 214 -> {215}; + 215 -> {217 216}; + 216 -> {227}; + 217 -> {218}; + 218 -> {219}; + 219 -> {220}; + 220 -> {221}; + 221 -> {222}; + 222 -> {223}; + 223 -> {224}; + 224 -> {225}; + 225 -> {226}; + 226 -> {227}; + 227 -> {228}; + 228 -> {229}; + 229 -> {230}; + 230 -> {231}; + 231 -> {232}; + 232 -> {233}; + 233 -> {235 234}; + 234 -> {245}; + 235 -> {236}; + 236 -> {237}; + 237 -> {238}; + 238 -> {239}; + 239 -> {240}; + 240 -> {241}; + 241 -> {242}; + 242 -> {243}; + 243 -> {244}; + 244 -> {245}; + 245 -> {246}; + 246 -> {247}; + 247 -> {248}; + 248 -> {249}; + 249 -> {250}; + 250 -> {251}; + 251 -> {253 252}; + 252 -> {263}; + 253 -> {254}; + 254 -> {255}; + 255 -> {256}; + 256 -> {257}; + 257 -> {258}; + 258 -> {259}; + 259 -> {260}; + 260 -> {261}; + 261 -> {262}; + 262 -> {263}; + 263 -> {264}; + 264 -> {265}; + 265 -> {266}; + 266 -> {267}; + 267 -> {268}; + 268 -> {269}; + 269 -> {270}; + 270 -> {271}; + 271 -> {273 272}; + 272 -> {283}; + 273 -> {274}; + 274 -> {275}; + 275 -> {276}; + 276 -> {277}; + 277 -> {278}; + 278 -> {279}; + 279 -> {280}; + 280 -> {281}; + 281 -> {282}; + 282 -> {283}; + 283 -> {284}; + 284 -> {285}; + 285 -> {286}; + 286 -> {287}; + 287 -> {288}; + 288 -> {289}; + 289 -> {291 290}; + 290 -> {301}; + 291 -> {292}; + 292 -> {293}; + 293 -> {294}; + 294 -> {295}; + 295 -> {296}; + 296 -> {297}; + 297 -> {298}; + 298 -> {299}; + 299 -> {300}; + 300 -> {301}; + 301 -> {302}; + 302 -> {303}; + 303 -> {304}; + 304 -> {305}; + 305 -> {306}; + 306 -> {307}; + 307 -> {309 308}; + 308 -> {319}; + 309 -> {310}; + 310 -> {311}; + 311 -> {312}; + 312 -> {313}; + 313 -> {314}; + 314 -> {315}; + 315 -> {316}; + 316 -> {317}; + 317 -> {318}; + 318 -> {319}; + 319 -> {320}; + 320 -> {321}; -} + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot index 4a7ac514c75..113070b187a 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot @@ -71,1369 +71,1383 @@ digraph nullability_kt { 18 [label="Enter class QImpl" style="filled" fillcolor=red]; subgraph cluster_10 { color=blue - 20 [label="Enter property" style="filled" fillcolor=red]; - 21 [label="Access variable R|/data|"]; - 22 [label="Exit property" style="filled" fillcolor=red]; + 19 [label="Part of class initialization"]; + 20 [label="Exit class QImpl" style="filled" fillcolor=red]; } - 19 [label="Exit class QImpl" style="filled" fillcolor=red]; - } - 18 -> {20} [color=green]; - 20 -> {21}; - 21 -> {22}; - 22 -> {19} [color=green]; + 18 -> {19} [color=green]; + 19 -> {20} [style=dotted]; + 19 -> {26} [color=green]; + 19 -> {26} [style=dashed]; - subgraph cluster_11 { - color=red - 23 [label="Enter function " style="filled" fillcolor=red]; - 24 [label="Delegated constructor call: super()"]; - 25 [label="Exit function " style="filled" fillcolor=red]; - } - 23 -> {24}; - 24 -> {25}; + subgraph cluster_11 { + color=red + 21 [label="Enter function " style="filled" fillcolor=red]; + 22 [label="Delegated constructor call: super()"]; + 23 [label="Exit function " style="filled" fillcolor=red]; + } + 21 -> {22}; + 22 -> {23}; - subgraph cluster_12 { - color=red - 26 [label="Enter function getter" style="filled" fillcolor=red]; - 27 [label="Exit function getter" style="filled" fillcolor=red]; - } - 26 -> {27}; + subgraph cluster_12 { + color=red + 24 [label="Enter function getter" style="filled" fillcolor=red]; + 25 [label="Exit function getter" style="filled" fillcolor=red]; + } + 24 -> {25}; + + subgraph cluster_13 { + color=red + 26 [label="Enter property" style="filled" fillcolor=red]; + 27 [label="Access variable R|/data|"]; + 28 [label="Exit property" style="filled" fillcolor=red]; + } + 26 -> {27}; + 27 -> {28}; + 28 -> {20} [color=green]; - subgraph cluster_13 { - color=red - 28 [label="Enter function fdata" style="filled" fillcolor=red]; subgraph cluster_14 { - color=blue - 29 [label="Enter block"]; - 30 [label="Const: Null(null)"]; - 31 [label="Jump: ^fdata Null(null)"]; - 32 [label="Stub" style="filled" fillcolor=gray]; - 33 [label="Exit block" style="filled" fillcolor=gray]; - } - 34 [label="Exit function fdata" style="filled" fillcolor=red]; - } - 28 -> {29}; - 29 -> {30}; - 30 -> {31}; - 31 -> {34}; - 31 -> {32} [style=dotted]; - 32 -> {33} [style=dotted]; - 33 -> {34} [style=dotted]; - - subgraph cluster_15 { - color=red - 35 [label="Enter class QImplMutable" style="filled" fillcolor=red]; - subgraph cluster_16 { - color=blue - 37 [label="Enter property" style="filled" fillcolor=red]; - 38 [label="Access variable R|/data|"]; - 39 [label="Exit property" style="filled" fillcolor=red]; - } - 36 [label="Exit class QImplMutable" style="filled" fillcolor=red]; - } - 35 -> {37} [color=green]; - 37 -> {38}; - 38 -> {39}; - 39 -> {36} [color=green]; - - subgraph cluster_17 { - color=red - 40 [label="Enter function " style="filled" fillcolor=red]; - 41 [label="Delegated constructor call: super()"]; - 42 [label="Exit function " style="filled" fillcolor=red]; - } - 40 -> {41}; - 41 -> {42}; - - subgraph cluster_18 { - color=red - 43 [label="Enter function getter" style="filled" fillcolor=red]; - 44 [label="Exit function getter" style="filled" fillcolor=red]; - } - 43 -> {44}; - - subgraph cluster_19 { - color=red - 45 [label="Enter function setter" style="filled" fillcolor=red]; - 46 [label="Exit function setter" style="filled" fillcolor=red]; - } - 45 -> {46}; - - subgraph cluster_20 { - color=red - 47 [label="Enter function fdata" style="filled" fillcolor=red]; - subgraph cluster_21 { - color=blue - 48 [label="Enter block"]; - 49 [label="Const: Null(null)"]; - 50 [label="Jump: ^fdata Null(null)"]; - 51 [label="Stub" style="filled" fillcolor=gray]; - 52 [label="Exit block" style="filled" fillcolor=gray]; - } - 53 [label="Exit function fdata" style="filled" fillcolor=red]; - } - 47 -> {48}; - 48 -> {49}; - 49 -> {50}; - 50 -> {53}; - 50 -> {51} [style=dotted]; - 51 -> {52} [style=dotted]; - 52 -> {53} [style=dotted]; - - subgraph cluster_22 { - color=red - 54 [label="Enter class QImplWithCustomGetter" style="filled" fillcolor=red]; - 55 [label="Exit class QImplWithCustomGetter" style="filled" fillcolor=red]; - } - 54 -> {55} [color=green]; - - subgraph cluster_23 { - color=red - 56 [label="Enter function " style="filled" fillcolor=red]; - 57 [label="Delegated constructor call: super()"]; - 58 [label="Exit function " style="filled" fillcolor=red]; - } - 56 -> {57}; - 57 -> {58}; - - subgraph cluster_24 { - color=red - 59 [label="Enter function getter" style="filled" fillcolor=red]; - subgraph cluster_25 { - color=blue - 60 [label="Enter block"]; - 61 [label="Const: Null(null)"]; - 62 [label="Jump: ^ Null(null)"]; - 63 [label="Stub" style="filled" fillcolor=gray]; - 64 [label="Exit block" style="filled" fillcolor=gray]; - } - 65 [label="Exit function getter" style="filled" fillcolor=red]; - } - 59 -> {60}; - 60 -> {61}; - 61 -> {62}; - 62 -> {65}; - 62 -> {63} [style=dotted]; - 63 -> {64} [style=dotted]; - 64 -> {65} [style=dotted]; - - subgraph cluster_26 { - color=red - 66 [label="Enter function fdata" style="filled" fillcolor=red]; - subgraph cluster_27 { - color=blue - 67 [label="Enter block"]; - 68 [label="Const: Null(null)"]; - 69 [label="Jump: ^fdata Null(null)"]; - 70 [label="Stub" style="filled" fillcolor=gray]; - 71 [label="Exit block" style="filled" fillcolor=gray]; - } - 72 [label="Exit function fdata" style="filled" fillcolor=red]; - } - 66 -> {67}; - 67 -> {68}; - 68 -> {69}; - 69 -> {72}; - 69 -> {70} [style=dotted]; - 70 -> {71} [style=dotted]; - 71 -> {72} [style=dotted]; - - subgraph cluster_28 { - color=red - 73 [label="Enter function test_1" style="filled" fillcolor=red]; - subgraph cluster_29 { - color=blue - 74 [label="Enter block"]; - subgraph cluster_30 { + color=red + 29 [label="Enter function fdata" style="filled" fillcolor=red]; + subgraph cluster_15 { color=blue - 75 [label="Enter when"]; + 30 [label="Enter block"]; + 31 [label="Const: Null(null)"]; + 32 [label="Jump: ^fdata Null(null)"]; + 33 [label="Stub" style="filled" fillcolor=gray]; + 34 [label="Exit block" style="filled" fillcolor=gray]; + } + 35 [label="Exit function fdata" style="filled" fillcolor=red]; + } + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {35}; + 32 -> {33} [style=dotted]; + 33 -> {34} [style=dotted]; + 34 -> {35} [style=dotted]; + + subgraph cluster_16 { + color=red + 36 [label="Enter class QImplMutable" style="filled" fillcolor=red]; + subgraph cluster_17 { + color=blue + 37 [label="Part of class initialization"]; + 38 [label="Exit class QImplMutable" style="filled" fillcolor=red]; + } + 36 -> {37} [color=green]; + 37 -> {38} [style=dotted]; + 37 -> {46} [color=green]; + 37 -> {46} [style=dashed]; + + subgraph cluster_18 { + color=red + 39 [label="Enter function " style="filled" fillcolor=red]; + 40 [label="Delegated constructor call: super()"]; + 41 [label="Exit function " style="filled" fillcolor=red]; + } + 39 -> {40}; + 40 -> {41}; + + subgraph cluster_19 { + color=red + 42 [label="Enter function getter" style="filled" fillcolor=red]; + 43 [label="Exit function getter" style="filled" fillcolor=red]; + } + 42 -> {43}; + + subgraph cluster_20 { + color=red + 44 [label="Enter function setter" style="filled" fillcolor=red]; + 45 [label="Exit function setter" style="filled" fillcolor=red]; + } + 44 -> {45}; + + subgraph cluster_21 { + color=red + 46 [label="Enter property" style="filled" fillcolor=red]; + 47 [label="Access variable R|/data|"]; + 48 [label="Exit property" style="filled" fillcolor=red]; + } + 46 -> {47}; + 47 -> {48}; + 48 -> {38} [color=green]; + + subgraph cluster_22 { + color=red + 49 [label="Enter function fdata" style="filled" fillcolor=red]; + subgraph cluster_23 { + color=blue + 50 [label="Enter block"]; + 51 [label="Const: Null(null)"]; + 52 [label="Jump: ^fdata Null(null)"]; + 53 [label="Stub" style="filled" fillcolor=gray]; + 54 [label="Exit block" style="filled" fillcolor=gray]; + } + 55 [label="Exit function fdata" style="filled" fillcolor=red]; + } + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {55}; + 52 -> {53} [style=dotted]; + 53 -> {54} [style=dotted]; + 54 -> {55} [style=dotted]; + + subgraph cluster_24 { + color=red + 56 [label="Enter class QImplWithCustomGetter" style="filled" fillcolor=red]; + 57 [label="Exit class QImplWithCustomGetter" style="filled" fillcolor=red]; + } + 56 -> {57} [color=green]; + + subgraph cluster_25 { + color=red + 58 [label="Enter function " style="filled" fillcolor=red]; + 59 [label="Delegated constructor call: super()"]; + 60 [label="Exit function " style="filled" fillcolor=red]; + } + 58 -> {59}; + 59 -> {60}; + + subgraph cluster_26 { + color=red + 61 [label="Enter function getter" style="filled" fillcolor=red]; + subgraph cluster_27 { + color=blue + 62 [label="Enter block"]; + 63 [label="Const: Null(null)"]; + 64 [label="Jump: ^ Null(null)"]; + 65 [label="Stub" style="filled" fillcolor=gray]; + 66 [label="Exit block" style="filled" fillcolor=gray]; + } + 67 [label="Exit function getter" style="filled" fillcolor=red]; + } + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {67}; + 64 -> {65} [style=dotted]; + 65 -> {66} [style=dotted]; + 66 -> {67} [style=dotted]; + + subgraph cluster_28 { + color=red + 68 [label="Enter function fdata" style="filled" fillcolor=red]; + subgraph cluster_29 { + color=blue + 69 [label="Enter block"]; + 70 [label="Const: Null(null)"]; + 71 [label="Jump: ^fdata Null(null)"]; + 72 [label="Stub" style="filled" fillcolor=gray]; + 73 [label="Exit block" style="filled" fillcolor=gray]; + } + 74 [label="Exit function fdata" style="filled" fillcolor=red]; + } + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {74}; + 71 -> {72} [style=dotted]; + 72 -> {73} [style=dotted]; + 73 -> {74} [style=dotted]; + + subgraph cluster_30 { + color=red + 75 [label="Enter function test_1" style="filled" fillcolor=red]; subgraph cluster_31 { color=blue - 76 [label="Enter when branch condition "]; - 77 [label="Access variable R|/x|"]; - 78 [label="Const: Null(null)"]; - 79 [label="Equality operator !="]; - 80 [label="Exit when branch condition"]; + 76 [label="Enter block"]; + subgraph cluster_32 { + color=blue + 77 [label="Enter when"]; + subgraph cluster_33 { + color=blue + 78 [label="Enter when branch condition "]; + 79 [label="Access variable R|/x|"]; + 80 [label="Const: Null(null)"]; + 81 [label="Equality operator !="]; + 82 [label="Exit when branch condition"]; + } + subgraph cluster_34 { + color=blue + 83 [label="Enter when branch condition else"]; + 84 [label="Exit when branch condition"]; + } + 85 [label="Enter when branch result"]; + subgraph cluster_35 { + color=blue + 86 [label="Enter block"]; + 87 [label="Access variable R|/x|"]; + 88 [label="Function call: R|/x|.#()"]; + 89 [label="Exit block"]; + } + 90 [label="Exit when branch result"]; + 91 [label="Enter when branch result"]; + subgraph cluster_36 { + color=blue + 92 [label="Enter block"]; + 93 [label="Access variable R|/x|"]; + 94 [label="Function call: R|/x|.R|/A.foo|()"]; + 95 [label="Exit block"]; + } + 96 [label="Exit when branch result"]; + 97 [label="Exit when"]; + } + 98 [label="Access variable R|/x|"]; + 99 [label="Function call: R|/x|.#()"]; + 100 [label="Exit block"]; } - subgraph cluster_32 { - color=blue - 81 [label="Enter when branch condition else"]; - 82 [label="Exit when branch condition"]; - } - 83 [label="Enter when branch result"]; - subgraph cluster_33 { - color=blue - 84 [label="Enter block"]; - 85 [label="Access variable R|/x|"]; - 86 [label="Function call: R|/x|.#()"]; - 87 [label="Exit block"]; - } - 88 [label="Exit when branch result"]; - 89 [label="Enter when branch result"]; - subgraph cluster_34 { - color=blue - 90 [label="Enter block"]; - 91 [label="Access variable R|/x|"]; - 92 [label="Function call: R|/x|.R|/A.foo|()"]; - 93 [label="Exit block"]; - } - 94 [label="Exit when branch result"]; - 95 [label="Exit when"]; + 101 [label="Exit function test_1" style="filled" fillcolor=red]; } - 96 [label="Access variable R|/x|"]; - 97 [label="Function call: R|/x|.#()"]; - 98 [label="Exit block"]; - } - 99 [label="Exit function test_1" style="filled" fillcolor=red]; - } - 73 -> {74}; - 74 -> {75}; - 75 -> {76}; - 76 -> {77}; - 77 -> {78}; - 78 -> {79}; - 79 -> {80}; - 80 -> {89 81}; - 81 -> {82}; - 82 -> {83}; - 83 -> {84}; - 84 -> {85}; - 85 -> {86}; - 86 -> {87}; - 87 -> {88}; - 88 -> {95}; - 89 -> {90}; - 90 -> {91}; - 91 -> {92}; - 92 -> {93}; - 93 -> {94}; - 94 -> {95}; - 95 -> {96}; - 96 -> {97}; - 97 -> {98}; - 98 -> {99}; + 75 -> {76}; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {91 83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {97}; + 91 -> {92}; + 92 -> {93}; + 93 -> {94}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {100}; + 100 -> {101}; - subgraph cluster_35 { - color=red - 100 [label="Enter function test_2" style="filled" fillcolor=red]; - subgraph cluster_36 { - color=blue - 101 [label="Enter block"]; subgraph cluster_37 { - color=blue - 102 [label="Enter when"]; + color=red + 102 [label="Enter function test_2" style="filled" fillcolor=red]; subgraph cluster_38 { color=blue - 103 [label="Enter when branch condition "]; - 104 [label="Access variable R|/x|"]; - 105 [label="Const: Null(null)"]; - 106 [label="Equality operator =="]; - 107 [label="Exit when branch condition"]; + 103 [label="Enter block"]; + subgraph cluster_39 { + color=blue + 104 [label="Enter when"]; + subgraph cluster_40 { + color=blue + 105 [label="Enter when branch condition "]; + 106 [label="Access variable R|/x|"]; + 107 [label="Const: Null(null)"]; + 108 [label="Equality operator =="]; + 109 [label="Exit when branch condition"]; + } + subgraph cluster_41 { + color=blue + 110 [label="Enter when branch condition else"]; + 111 [label="Exit when branch condition"]; + } + 112 [label="Enter when branch result"]; + subgraph cluster_42 { + color=blue + 113 [label="Enter block"]; + 114 [label="Access variable R|/x|"]; + 115 [label="Function call: R|/x|.R|/A.foo|()"]; + 116 [label="Exit block"]; + } + 117 [label="Exit when branch result"]; + 118 [label="Enter when branch result"]; + subgraph cluster_43 { + color=blue + 119 [label="Enter block"]; + 120 [label="Access variable R|/x|"]; + 121 [label="Function call: R|/x|.#()"]; + 122 [label="Exit block"]; + } + 123 [label="Exit when branch result"]; + 124 [label="Exit when"]; + } + 125 [label="Access variable R|/x|"]; + 126 [label="Function call: R|/x|.#()"]; + 127 [label="Exit block"]; } - subgraph cluster_39 { - color=blue - 108 [label="Enter when branch condition else"]; - 109 [label="Exit when branch condition"]; - } - 110 [label="Enter when branch result"]; - subgraph cluster_40 { - color=blue - 111 [label="Enter block"]; - 112 [label="Access variable R|/x|"]; - 113 [label="Function call: R|/x|.R|/A.foo|()"]; - 114 [label="Exit block"]; - } - 115 [label="Exit when branch result"]; - 116 [label="Enter when branch result"]; - subgraph cluster_41 { - color=blue - 117 [label="Enter block"]; - 118 [label="Access variable R|/x|"]; - 119 [label="Function call: R|/x|.#()"]; - 120 [label="Exit block"]; - } - 121 [label="Exit when branch result"]; - 122 [label="Exit when"]; + 128 [label="Exit function test_2" style="filled" fillcolor=red]; } - 123 [label="Access variable R|/x|"]; - 124 [label="Function call: R|/x|.#()"]; - 125 [label="Exit block"]; - } - 126 [label="Exit function test_2" style="filled" fillcolor=red]; - } - 100 -> {101}; - 101 -> {102}; - 102 -> {103}; - 103 -> {104}; - 104 -> {105}; - 105 -> {106}; - 106 -> {107}; - 107 -> {116 108}; - 108 -> {109}; - 109 -> {110}; - 110 -> {111}; - 111 -> {112}; - 112 -> {113}; - 113 -> {114}; - 114 -> {115}; - 115 -> {122}; - 116 -> {117}; - 117 -> {118}; - 118 -> {119}; - 119 -> {120}; - 120 -> {121}; - 121 -> {122}; - 122 -> {123}; - 123 -> {124}; - 124 -> {125}; - 125 -> {126}; + 102 -> {103}; + 103 -> {104}; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {118 110}; + 110 -> {111}; + 111 -> {112}; + 112 -> {113}; + 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {124}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; - subgraph cluster_42 { - color=red - 127 [label="Enter function test_3" style="filled" fillcolor=red]; - subgraph cluster_43 { - color=blue - 128 [label="Enter block"]; - 129 [label="Access variable R|/x|"]; - 130 [label="Exit lhs of ?:"]; - 131 [label="Enter rhs of ?:"]; - 132 [label="Jump: ^test_3 Unit"]; - 133 [label="Stub" style="filled" fillcolor=gray]; - 134 [label="Lhs of ?: is not null"]; - 135 [label="Exit ?:"]; - 136 [label="Access variable R|/x|"]; - 137 [label="Function call: R|/x|.R|/A.foo|()"]; - 138 [label="Exit block"]; - } - 139 [label="Exit function test_3" style="filled" fillcolor=red]; - } - 127 -> {128}; - 128 -> {129}; - 129 -> {130}; - 130 -> {134 131}; - 131 -> {132}; - 132 -> {139}; - 132 -> {133} [style=dotted]; - 133 -> {135} [style=dotted]; - 134 -> {135}; - 135 -> {136}; - 136 -> {137}; - 137 -> {138}; - 138 -> {139}; + subgraph cluster_44 { + color=red + 129 [label="Enter function test_3" style="filled" fillcolor=red]; + subgraph cluster_45 { + color=blue + 130 [label="Enter block"]; + 131 [label="Access variable R|/x|"]; + 132 [label="Exit lhs of ?:"]; + 133 [label="Enter rhs of ?:"]; + 134 [label="Jump: ^test_3 Unit"]; + 135 [label="Stub" style="filled" fillcolor=gray]; + 136 [label="Lhs of ?: is not null"]; + 137 [label="Exit ?:"]; + 138 [label="Access variable R|/x|"]; + 139 [label="Function call: R|/x|.R|/A.foo|()"]; + 140 [label="Exit block"]; + } + 141 [label="Exit function test_3" style="filled" fillcolor=red]; + } + 129 -> {130}; + 130 -> {131}; + 131 -> {132}; + 132 -> {136 133}; + 133 -> {134}; + 134 -> {141}; + 134 -> {135} [style=dotted]; + 135 -> {137} [style=dotted]; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; + 139 -> {140}; + 140 -> {141}; - subgraph cluster_44 { - color=red - 140 [label="Enter function test_4" style="filled" fillcolor=red]; - subgraph cluster_45 { - color=blue - 141 [label="Enter block"]; subgraph cluster_46 { - color=blue - 142 [label="Enter when"]; + color=red + 142 [label="Enter function test_4" style="filled" fillcolor=red]; subgraph cluster_47 { color=blue - 143 [label="Enter when branch condition "]; - 144 [label="Access variable R|/x|"]; - 145 [label="Enter safe call"]; - 146 [label="Function call: $subj$.R|/A.getA|()"]; - 147 [label="Exit safe call"]; - 148 [label="Const: Null(null)"]; - 149 [label="Equality operator =="]; - 150 [label="Exit when branch condition"]; + 143 [label="Enter block"]; + subgraph cluster_48 { + color=blue + 144 [label="Enter when"]; + subgraph cluster_49 { + color=blue + 145 [label="Enter when branch condition "]; + 146 [label="Access variable R|/x|"]; + 147 [label="Enter safe call"]; + 148 [label="Function call: $subj$.R|/A.getA|()"]; + 149 [label="Exit safe call"]; + 150 [label="Const: Null(null)"]; + 151 [label="Equality operator =="]; + 152 [label="Exit when branch condition"]; + } + 153 [label="Synthetic else branch"]; + 154 [label="Enter when branch result"]; + subgraph cluster_50 { + color=blue + 155 [label="Enter block"]; + 156 [label="Jump: ^test_4 Unit"]; + 157 [label="Stub" style="filled" fillcolor=gray]; + 158 [label="Exit block" style="filled" fillcolor=gray]; + } + 159 [label="Exit when branch result" style="filled" fillcolor=gray]; + 160 [label="Exit when"]; + } + 161 [label="Access variable R|/x|"]; + 162 [label="Function call: R|/x|.R|/A.foo|()"]; + 163 [label="Exit block"]; } - 151 [label="Synthetic else branch"]; - 152 [label="Enter when branch result"]; - subgraph cluster_48 { - color=blue - 153 [label="Enter block"]; - 154 [label="Jump: ^test_4 Unit"]; - 155 [label="Stub" style="filled" fillcolor=gray]; - 156 [label="Exit block" style="filled" fillcolor=gray]; - } - 157 [label="Exit when branch result" style="filled" fillcolor=gray]; - 158 [label="Exit when"]; + 164 [label="Exit function test_4" style="filled" fillcolor=red]; } - 159 [label="Access variable R|/x|"]; - 160 [label="Function call: R|/x|.R|/A.foo|()"]; - 161 [label="Exit block"]; - } - 162 [label="Exit function test_4" style="filled" fillcolor=red]; - } - 140 -> {141}; - 141 -> {142}; - 142 -> {143}; - 143 -> {144}; - 144 -> {145 147}; - 145 -> {146}; - 146 -> {147}; - 147 -> {148}; - 148 -> {149}; - 149 -> {150}; - 150 -> {152 151}; - 151 -> {158}; - 152 -> {153}; - 153 -> {154}; - 154 -> {162}; - 154 -> {155} [style=dotted]; - 155 -> {156} [style=dotted]; - 156 -> {157} [style=dotted]; - 157 -> {158} [style=dotted]; - 158 -> {159}; - 159 -> {160}; - 160 -> {161}; - 161 -> {162}; + 142 -> {143}; + 143 -> {144}; + 144 -> {145}; + 145 -> {146}; + 146 -> {147 149}; + 147 -> {148}; + 148 -> {149}; + 149 -> {150}; + 150 -> {151}; + 151 -> {152}; + 152 -> {154 153}; + 153 -> {160}; + 154 -> {155}; + 155 -> {156}; + 156 -> {164}; + 156 -> {157} [style=dotted]; + 157 -> {158} [style=dotted]; + 158 -> {159} [style=dotted]; + 159 -> {160} [style=dotted]; + 160 -> {161}; + 161 -> {162}; + 162 -> {163}; + 163 -> {164}; - subgraph cluster_49 { - color=red - 163 [label="Enter function test_5" style="filled" fillcolor=red]; - subgraph cluster_50 { - color=blue - 164 [label="Enter block"]; subgraph cluster_51 { - color=blue - 165 [label="Enter when"]; + color=red + 165 [label="Enter function test_5" style="filled" fillcolor=red]; subgraph cluster_52 { color=blue - 166 [label="Enter when branch condition "]; - 167 [label="Access variable R|/q|"]; - 168 [label="Enter safe call"]; - 169 [label="Access variable R|/Q.data|"]; - 170 [label="Exit safe call"]; - 171 [label="Enter safe call"]; - 172 [label="Access variable R|/MyData.s|"]; - 173 [label="Exit safe call"]; - 174 [label="Enter safe call"]; - 175 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; - 176 [label="Exit safe call"]; - 177 [label="Const: Null(null)"]; - 178 [label="Equality operator !="]; - 179 [label="Exit when branch condition"]; + 166 [label="Enter block"]; + subgraph cluster_53 { + color=blue + 167 [label="Enter when"]; + subgraph cluster_54 { + color=blue + 168 [label="Enter when branch condition "]; + 169 [label="Access variable R|/q|"]; + 170 [label="Enter safe call"]; + 171 [label="Access variable R|/Q.data|"]; + 172 [label="Exit safe call"]; + 173 [label="Enter safe call"]; + 174 [label="Access variable R|/MyData.s|"]; + 175 [label="Exit safe call"]; + 176 [label="Enter safe call"]; + 177 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; + 178 [label="Exit safe call"]; + 179 [label="Const: Null(null)"]; + 180 [label="Equality operator !="]; + 181 [label="Exit when branch condition"]; + } + 182 [label="Synthetic else branch"]; + 183 [label="Enter when branch result"]; + subgraph cluster_55 { + color=blue + 184 [label="Enter block"]; + 185 [label="Access variable R|/q|"]; + 186 [label="Access variable R|/Q.data|"]; + 187 [label="Access variable R|/q|"]; + 188 [label="Access variable R|/Q.data|"]; + 189 [label="Access variable #"]; + 190 [label="Access variable R|/q|"]; + 191 [label="Access variable R|/Q.data|"]; + 192 [label="Access variable #"]; + 193 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; + 194 [label="Exit block"]; + } + 195 [label="Exit when branch result"]; + 196 [label="Exit when"]; + } + 197 [label="Exit block"]; } - 180 [label="Synthetic else branch"]; - 181 [label="Enter when branch result"]; - subgraph cluster_53 { - color=blue - 182 [label="Enter block"]; - 183 [label="Access variable R|/q|"]; - 184 [label="Access variable R|/Q.data|"]; - 185 [label="Access variable R|/q|"]; - 186 [label="Access variable R|/Q.data|"]; - 187 [label="Access variable #"]; - 188 [label="Access variable R|/q|"]; - 189 [label="Access variable R|/Q.data|"]; - 190 [label="Access variable #"]; - 191 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; - 192 [label="Exit block"]; - } - 193 [label="Exit when branch result"]; - 194 [label="Exit when"]; + 198 [label="Exit function test_5" style="filled" fillcolor=red]; } - 195 [label="Exit block"]; - } - 196 [label="Exit function test_5" style="filled" fillcolor=red]; - } - 163 -> {164}; - 164 -> {165}; - 165 -> {166}; - 166 -> {167}; - 167 -> {168 170}; - 168 -> {169}; - 169 -> {170}; - 170 -> {171 173}; - 171 -> {172}; - 172 -> {173}; - 173 -> {174 176}; - 174 -> {175}; - 175 -> {176}; - 176 -> {177}; - 177 -> {178}; - 178 -> {179}; - 179 -> {181 180}; - 180 -> {194}; - 181 -> {182}; - 182 -> {183}; - 183 -> {184}; - 184 -> {185}; - 185 -> {186}; - 186 -> {187}; - 187 -> {188}; - 188 -> {189}; - 189 -> {190}; - 190 -> {191}; - 191 -> {192}; - 192 -> {193}; - 193 -> {194}; - 194 -> {195}; - 195 -> {196}; + 165 -> {166}; + 166 -> {167}; + 167 -> {168}; + 168 -> {169}; + 169 -> {170 172}; + 170 -> {171}; + 171 -> {172}; + 172 -> {173 175}; + 173 -> {174}; + 174 -> {175}; + 175 -> {176 178}; + 176 -> {177}; + 177 -> {178}; + 178 -> {179}; + 179 -> {180}; + 180 -> {181}; + 181 -> {183 182}; + 182 -> {196}; + 183 -> {184}; + 184 -> {185}; + 185 -> {186}; + 186 -> {187}; + 187 -> {188}; + 188 -> {189}; + 189 -> {190}; + 190 -> {191}; + 191 -> {192}; + 192 -> {193}; + 193 -> {194}; + 194 -> {195}; + 195 -> {196}; + 196 -> {197}; + 197 -> {198}; - subgraph cluster_54 { - color=red - 197 [label="Enter function test_6" style="filled" fillcolor=red]; - subgraph cluster_55 { - color=blue - 198 [label="Enter block"]; - 199 [label="Access variable R|/q|"]; - 200 [label="Enter safe call"]; - 201 [label="Access variable R|/Q.data|"]; - 202 [label="Exit safe call"]; - 203 [label="Enter safe call"]; - 204 [label="Access variable R|/MyData.s|"]; - 205 [label="Exit safe call"]; - 206 [label="Enter safe call"]; - 207 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; - 208 [label="Exit safe call"]; - 209 [label="Exit lhs of ?:"]; - 210 [label="Enter rhs of ?:"]; - 211 [label="Jump: ^test_6 Unit"]; - 212 [label="Stub" style="filled" fillcolor=gray]; - 213 [label="Lhs of ?: is not null"]; - 214 [label="Exit ?:"]; - 215 [label="Access variable R|/q|"]; - 216 [label="Access variable R|/Q.data|"]; - 217 [label="Access variable R|/q|"]; - 218 [label="Access variable R|/Q.data|"]; - 219 [label="Access variable #"]; - 220 [label="Access variable R|/q|"]; - 221 [label="Access variable R|/Q.data|"]; - 222 [label="Access variable #"]; - 223 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; - 224 [label="Exit block"]; - } - 225 [label="Exit function test_6" style="filled" fillcolor=red]; - } - 197 -> {198}; - 198 -> {199}; - 199 -> {200 202}; - 200 -> {201}; - 201 -> {202}; - 202 -> {203 205}; - 203 -> {204}; - 204 -> {205}; - 205 -> {206 208}; - 206 -> {207}; - 207 -> {208}; - 208 -> {209}; - 209 -> {213 210}; - 210 -> {211}; - 211 -> {225}; - 211 -> {212} [style=dotted]; - 212 -> {214} [style=dotted]; - 213 -> {214}; - 214 -> {215}; - 215 -> {216}; - 216 -> {217}; - 217 -> {218}; - 218 -> {219}; - 219 -> {220}; - 220 -> {221}; - 221 -> {222}; - 222 -> {223}; - 223 -> {224}; - 224 -> {225}; + subgraph cluster_56 { + color=red + 199 [label="Enter function test_6" style="filled" fillcolor=red]; + subgraph cluster_57 { + color=blue + 200 [label="Enter block"]; + 201 [label="Access variable R|/q|"]; + 202 [label="Enter safe call"]; + 203 [label="Access variable R|/Q.data|"]; + 204 [label="Exit safe call"]; + 205 [label="Enter safe call"]; + 206 [label="Access variable R|/MyData.s|"]; + 207 [label="Exit safe call"]; + 208 [label="Enter safe call"]; + 209 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; + 210 [label="Exit safe call"]; + 211 [label="Exit lhs of ?:"]; + 212 [label="Enter rhs of ?:"]; + 213 [label="Jump: ^test_6 Unit"]; + 214 [label="Stub" style="filled" fillcolor=gray]; + 215 [label="Lhs of ?: is not null"]; + 216 [label="Exit ?:"]; + 217 [label="Access variable R|/q|"]; + 218 [label="Access variable R|/Q.data|"]; + 219 [label="Access variable R|/q|"]; + 220 [label="Access variable R|/Q.data|"]; + 221 [label="Access variable #"]; + 222 [label="Access variable R|/q|"]; + 223 [label="Access variable R|/Q.data|"]; + 224 [label="Access variable #"]; + 225 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; + 226 [label="Exit block"]; + } + 227 [label="Exit function test_6" style="filled" fillcolor=red]; + } + 199 -> {200}; + 200 -> {201}; + 201 -> {202 204}; + 202 -> {203}; + 203 -> {204}; + 204 -> {205 207}; + 205 -> {206}; + 206 -> {207}; + 207 -> {208 210}; + 208 -> {209}; + 209 -> {210}; + 210 -> {211}; + 211 -> {215 212}; + 212 -> {213}; + 213 -> {227}; + 213 -> {214} [style=dotted]; + 214 -> {216} [style=dotted]; + 215 -> {216}; + 216 -> {217}; + 217 -> {218}; + 218 -> {219}; + 219 -> {220}; + 220 -> {221}; + 221 -> {222}; + 222 -> {223}; + 223 -> {224}; + 224 -> {225}; + 225 -> {226}; + 226 -> {227}; - subgraph cluster_56 { - color=red - 226 [label="Enter function test_7" style="filled" fillcolor=red]; - subgraph cluster_57 { - color=blue - 227 [label="Enter block"]; subgraph cluster_58 { - color=blue - 228 [label="Enter when"]; + color=red + 228 [label="Enter function test_7" style="filled" fillcolor=red]; subgraph cluster_59 { color=blue - 229 [label="Enter when branch condition "]; - 230 [label="Access variable R|/q|"]; - 231 [label="Enter safe call"]; - 232 [label="Function call: $subj$.R|/Q.fdata|()"]; - 233 [label="Exit safe call"]; - 234 [label="Enter safe call"]; - 235 [label="Function call: $subj$.R|/MyData.fs|()"]; - 236 [label="Exit safe call"]; - 237 [label="Enter safe call"]; - 238 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; - 239 [label="Exit safe call"]; - 240 [label="Const: Null(null)"]; - 241 [label="Equality operator !="]; - 242 [label="Exit when branch condition"]; + 229 [label="Enter block"]; + subgraph cluster_60 { + color=blue + 230 [label="Enter when"]; + subgraph cluster_61 { + color=blue + 231 [label="Enter when branch condition "]; + 232 [label="Access variable R|/q|"]; + 233 [label="Enter safe call"]; + 234 [label="Function call: $subj$.R|/Q.fdata|()"]; + 235 [label="Exit safe call"]; + 236 [label="Enter safe call"]; + 237 [label="Function call: $subj$.R|/MyData.fs|()"]; + 238 [label="Exit safe call"]; + 239 [label="Enter safe call"]; + 240 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; + 241 [label="Exit safe call"]; + 242 [label="Const: Null(null)"]; + 243 [label="Equality operator !="]; + 244 [label="Exit when branch condition"]; + } + 245 [label="Synthetic else branch"]; + 246 [label="Enter when branch result"]; + subgraph cluster_62 { + color=blue + 247 [label="Enter block"]; + 248 [label="Access variable R|/q|"]; + 249 [label="Function call: R|/q|.R|/Q.fdata|()"]; + 250 [label="Access variable R|/q|"]; + 251 [label="Function call: R|/q|.R|/Q.fdata|()"]; + 252 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; + 253 [label="Access variable R|/q|"]; + 254 [label="Function call: R|/q|.R|/Q.fdata|()"]; + 255 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; + 256 [label="Function call: R|/q|.R|/Q.fdata|().#().R|kotlin/Int.inc|()"]; + 257 [label="Exit block"]; + } + 258 [label="Exit when branch result"]; + 259 [label="Exit when"]; + } + 260 [label="Exit block"]; } - 243 [label="Synthetic else branch"]; - 244 [label="Enter when branch result"]; - subgraph cluster_60 { - color=blue - 245 [label="Enter block"]; - 246 [label="Access variable R|/q|"]; - 247 [label="Function call: R|/q|.R|/Q.fdata|()"]; - 248 [label="Access variable R|/q|"]; - 249 [label="Function call: R|/q|.R|/Q.fdata|()"]; - 250 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; - 251 [label="Access variable R|/q|"]; - 252 [label="Function call: R|/q|.R|/Q.fdata|()"]; - 253 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; - 254 [label="Function call: R|/q|.R|/Q.fdata|().#().R|kotlin/Int.inc|()"]; - 255 [label="Exit block"]; - } - 256 [label="Exit when branch result"]; - 257 [label="Exit when"]; + 261 [label="Exit function test_7" style="filled" fillcolor=red]; } - 258 [label="Exit block"]; - } - 259 [label="Exit function test_7" style="filled" fillcolor=red]; - } - 226 -> {227}; - 227 -> {228}; - 228 -> {229}; - 229 -> {230}; - 230 -> {231 233}; - 231 -> {232}; - 232 -> {233}; - 233 -> {234 236}; - 234 -> {235}; - 235 -> {236}; - 236 -> {237 239}; - 237 -> {238}; - 238 -> {239}; - 239 -> {240}; - 240 -> {241}; - 241 -> {242}; - 242 -> {244 243}; - 243 -> {257}; - 244 -> {245}; - 245 -> {246}; - 246 -> {247}; - 247 -> {248}; - 248 -> {249}; - 249 -> {250}; - 250 -> {251}; - 251 -> {252}; - 252 -> {253}; - 253 -> {254}; - 254 -> {255}; - 255 -> {256}; - 256 -> {257}; - 257 -> {258}; - 258 -> {259}; + 228 -> {229}; + 229 -> {230}; + 230 -> {231}; + 231 -> {232}; + 232 -> {233 235}; + 233 -> {234}; + 234 -> {235}; + 235 -> {236 238}; + 236 -> {237}; + 237 -> {238}; + 238 -> {239 241}; + 239 -> {240}; + 240 -> {241}; + 241 -> {242}; + 242 -> {243}; + 243 -> {244}; + 244 -> {246 245}; + 245 -> {259}; + 246 -> {247}; + 247 -> {248}; + 248 -> {249}; + 249 -> {250}; + 250 -> {251}; + 251 -> {252}; + 252 -> {253}; + 253 -> {254}; + 254 -> {255}; + 255 -> {256}; + 256 -> {257}; + 257 -> {258}; + 258 -> {259}; + 259 -> {260}; + 260 -> {261}; - subgraph cluster_61 { - color=red - 260 [label="Enter function test_8" style="filled" fillcolor=red]; - subgraph cluster_62 { - color=blue - 261 [label="Enter block"]; subgraph cluster_63 { - color=blue - 262 [label="Enter when"]; + color=red + 262 [label="Enter function test_8" style="filled" fillcolor=red]; subgraph cluster_64 { color=blue - 263 [label="Enter when branch condition "]; - 264 [label="Access variable R|/b|"]; - 265 [label="Const: Boolean(true)"]; - 266 [label="Equality operator =="]; - 267 [label="Exit when branch condition"]; + 263 [label="Enter block"]; + subgraph cluster_65 { + color=blue + 264 [label="Enter when"]; + subgraph cluster_66 { + color=blue + 265 [label="Enter when branch condition "]; + 266 [label="Access variable R|/b|"]; + 267 [label="Const: Boolean(true)"]; + 268 [label="Equality operator =="]; + 269 [label="Exit when branch condition"]; + } + 270 [label="Synthetic else branch"]; + 271 [label="Enter when branch result"]; + subgraph cluster_67 { + color=blue + 272 [label="Enter block"]; + 273 [label="Access variable R|/b|"]; + 274 [label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 275 [label="Exit block"]; + } + 276 [label="Exit when branch result"]; + 277 [label="Exit when"]; + } + 278 [label="Exit block"]; } - 268 [label="Synthetic else branch"]; - 269 [label="Enter when branch result"]; - subgraph cluster_65 { - color=blue - 270 [label="Enter block"]; - 271 [label="Access variable R|/b|"]; - 272 [label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; - 273 [label="Exit block"]; - } - 274 [label="Exit when branch result"]; - 275 [label="Exit when"]; + 279 [label="Exit function test_8" style="filled" fillcolor=red]; } - 276 [label="Exit block"]; - } - 277 [label="Exit function test_8" style="filled" fillcolor=red]; - } - 260 -> {261}; - 261 -> {262}; - 262 -> {263}; - 263 -> {264}; - 264 -> {265}; - 265 -> {266}; - 266 -> {267}; - 267 -> {269 268}; - 268 -> {275}; - 269 -> {270}; - 270 -> {271}; - 271 -> {272}; - 272 -> {273}; - 273 -> {274}; - 274 -> {275}; - 275 -> {276}; - 276 -> {277}; + 262 -> {263}; + 263 -> {264}; + 264 -> {265}; + 265 -> {266}; + 266 -> {267}; + 267 -> {268}; + 268 -> {269}; + 269 -> {271 270}; + 270 -> {277}; + 271 -> {272}; + 272 -> {273}; + 273 -> {274}; + 274 -> {275}; + 275 -> {276}; + 276 -> {277}; + 277 -> {278}; + 278 -> {279}; - subgraph cluster_66 { - color=red - 278 [label="Enter function test_9" style="filled" fillcolor=red]; - subgraph cluster_67 { - color=blue - 279 [label="Enter block"]; subgraph cluster_68 { - color=blue - 280 [label="Enter when"]; + color=red + 280 [label="Enter function test_9" style="filled" fillcolor=red]; subgraph cluster_69 { color=blue - 281 [label="Enter when branch condition "]; - 282 [label="Access variable R|/a|"]; - 283 [label="Access variable R|/b|"]; - 284 [label="Equality operator =="]; - 285 [label="Exit when branch condition"]; + 281 [label="Enter block"]; + subgraph cluster_70 { + color=blue + 282 [label="Enter when"]; + subgraph cluster_71 { + color=blue + 283 [label="Enter when branch condition "]; + 284 [label="Access variable R|/a|"]; + 285 [label="Access variable R|/b|"]; + 286 [label="Equality operator =="]; + 287 [label="Exit when branch condition"]; + } + 288 [label="Synthetic else branch"]; + 289 [label="Enter when branch result"]; + subgraph cluster_72 { + color=blue + 290 [label="Enter block"]; + 291 [label="Access variable R|/b|"]; + 292 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 293 [label="Exit block"]; + } + 294 [label="Exit when branch result"]; + 295 [label="Exit when"]; + } + 296 [label="Access variable R|/b|"]; + 297 [label="Function call: R|/b|.#()"]; + subgraph cluster_73 { + color=blue + 298 [label="Enter when"]; + subgraph cluster_74 { + color=blue + 299 [label="Enter when branch condition "]; + 300 [label="Access variable R|/a|"]; + 301 [label="Access variable R|/b|"]; + 302 [label="Equality operator ==="]; + 303 [label="Exit when branch condition"]; + } + 304 [label="Synthetic else branch"]; + 305 [label="Enter when branch result"]; + subgraph cluster_75 { + color=blue + 306 [label="Enter block"]; + 307 [label="Access variable R|/b|"]; + 308 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 309 [label="Exit block"]; + } + 310 [label="Exit when branch result"]; + 311 [label="Exit when"]; + } + 312 [label="Access variable R|/b|"]; + 313 [label="Function call: R|/b|.#()"]; + subgraph cluster_76 { + color=blue + 314 [label="Enter when"]; + subgraph cluster_77 { + color=blue + 315 [label="Enter when branch condition "]; + 316 [label="Access variable R|/b|"]; + 317 [label="Access variable R|/a|"]; + 318 [label="Equality operator =="]; + 319 [label="Exit when branch condition"]; + } + 320 [label="Synthetic else branch"]; + 321 [label="Enter when branch result"]; + subgraph cluster_78 { + color=blue + 322 [label="Enter block"]; + 323 [label="Access variable R|/b|"]; + 324 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 325 [label="Exit block"]; + } + 326 [label="Exit when branch result"]; + 327 [label="Exit when"]; + } + 328 [label="Access variable R|/b|"]; + 329 [label="Function call: R|/b|.#()"]; + subgraph cluster_79 { + color=blue + 330 [label="Enter when"]; + subgraph cluster_80 { + color=blue + 331 [label="Enter when branch condition "]; + 332 [label="Access variable R|/b|"]; + 333 [label="Access variable R|/a|"]; + 334 [label="Equality operator ==="]; + 335 [label="Exit when branch condition"]; + } + 336 [label="Synthetic else branch"]; + 337 [label="Enter when branch result"]; + subgraph cluster_81 { + color=blue + 338 [label="Enter block"]; + 339 [label="Access variable R|/b|"]; + 340 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 341 [label="Exit block"]; + } + 342 [label="Exit when branch result"]; + 343 [label="Exit when"]; + } + 344 [label="Access variable R|/b|"]; + 345 [label="Function call: R|/b|.#()"]; + 346 [label="Exit block"]; } - 286 [label="Synthetic else branch"]; - 287 [label="Enter when branch result"]; - subgraph cluster_70 { - color=blue - 288 [label="Enter block"]; - 289 [label="Access variable R|/b|"]; - 290 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 291 [label="Exit block"]; - } - 292 [label="Exit when branch result"]; - 293 [label="Exit when"]; + 347 [label="Exit function test_9" style="filled" fillcolor=red]; } - 294 [label="Access variable R|/b|"]; - 295 [label="Function call: R|/b|.#()"]; - subgraph cluster_71 { - color=blue - 296 [label="Enter when"]; - subgraph cluster_72 { - color=blue - 297 [label="Enter when branch condition "]; - 298 [label="Access variable R|/a|"]; - 299 [label="Access variable R|/b|"]; - 300 [label="Equality operator ==="]; - 301 [label="Exit when branch condition"]; - } - 302 [label="Synthetic else branch"]; - 303 [label="Enter when branch result"]; - subgraph cluster_73 { - color=blue - 304 [label="Enter block"]; - 305 [label="Access variable R|/b|"]; - 306 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 307 [label="Exit block"]; - } - 308 [label="Exit when branch result"]; - 309 [label="Exit when"]; - } - 310 [label="Access variable R|/b|"]; - 311 [label="Function call: R|/b|.#()"]; - subgraph cluster_74 { - color=blue - 312 [label="Enter when"]; - subgraph cluster_75 { - color=blue - 313 [label="Enter when branch condition "]; - 314 [label="Access variable R|/b|"]; - 315 [label="Access variable R|/a|"]; - 316 [label="Equality operator =="]; - 317 [label="Exit when branch condition"]; - } - 318 [label="Synthetic else branch"]; - 319 [label="Enter when branch result"]; - subgraph cluster_76 { - color=blue - 320 [label="Enter block"]; - 321 [label="Access variable R|/b|"]; - 322 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 323 [label="Exit block"]; - } - 324 [label="Exit when branch result"]; - 325 [label="Exit when"]; - } - 326 [label="Access variable R|/b|"]; - 327 [label="Function call: R|/b|.#()"]; - subgraph cluster_77 { - color=blue - 328 [label="Enter when"]; - subgraph cluster_78 { - color=blue - 329 [label="Enter when branch condition "]; - 330 [label="Access variable R|/b|"]; - 331 [label="Access variable R|/a|"]; - 332 [label="Equality operator ==="]; - 333 [label="Exit when branch condition"]; - } - 334 [label="Synthetic else branch"]; - 335 [label="Enter when branch result"]; - subgraph cluster_79 { - color=blue - 336 [label="Enter block"]; - 337 [label="Access variable R|/b|"]; - 338 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 339 [label="Exit block"]; - } - 340 [label="Exit when branch result"]; - 341 [label="Exit when"]; - } - 342 [label="Access variable R|/b|"]; - 343 [label="Function call: R|/b|.#()"]; - 344 [label="Exit block"]; - } - 345 [label="Exit function test_9" style="filled" fillcolor=red]; - } - 278 -> {279}; - 279 -> {280}; - 280 -> {281}; - 281 -> {282}; - 282 -> {283}; - 283 -> {284}; - 284 -> {285}; - 285 -> {287 286}; - 286 -> {293}; - 287 -> {288}; - 288 -> {289}; - 289 -> {290}; - 290 -> {291}; - 291 -> {292}; - 292 -> {293}; - 293 -> {294}; - 294 -> {295}; - 295 -> {296}; - 296 -> {297}; - 297 -> {298}; - 298 -> {299}; - 299 -> {300}; - 300 -> {301}; - 301 -> {303 302}; - 302 -> {309}; - 303 -> {304}; - 304 -> {305}; - 305 -> {306}; - 306 -> {307}; - 307 -> {308}; - 308 -> {309}; - 309 -> {310}; - 310 -> {311}; - 311 -> {312}; - 312 -> {313}; - 313 -> {314}; - 314 -> {315}; - 315 -> {316}; - 316 -> {317}; - 317 -> {319 318}; - 318 -> {325}; - 319 -> {320}; - 320 -> {321}; - 321 -> {322}; - 322 -> {323}; - 323 -> {324}; - 324 -> {325}; - 325 -> {326}; - 326 -> {327}; - 327 -> {328}; - 328 -> {329}; - 329 -> {330}; - 330 -> {331}; - 331 -> {332}; - 332 -> {333}; - 333 -> {335 334}; - 334 -> {341}; - 335 -> {336}; - 336 -> {337}; - 337 -> {338}; - 338 -> {339}; - 339 -> {340}; - 340 -> {341}; - 341 -> {342}; - 342 -> {343}; - 343 -> {344}; - 344 -> {345}; + 280 -> {281}; + 281 -> {282}; + 282 -> {283}; + 283 -> {284}; + 284 -> {285}; + 285 -> {286}; + 286 -> {287}; + 287 -> {289 288}; + 288 -> {295}; + 289 -> {290}; + 290 -> {291}; + 291 -> {292}; + 292 -> {293}; + 293 -> {294}; + 294 -> {295}; + 295 -> {296}; + 296 -> {297}; + 297 -> {298}; + 298 -> {299}; + 299 -> {300}; + 300 -> {301}; + 301 -> {302}; + 302 -> {303}; + 303 -> {305 304}; + 304 -> {311}; + 305 -> {306}; + 306 -> {307}; + 307 -> {308}; + 308 -> {309}; + 309 -> {310}; + 310 -> {311}; + 311 -> {312}; + 312 -> {313}; + 313 -> {314}; + 314 -> {315}; + 315 -> {316}; + 316 -> {317}; + 317 -> {318}; + 318 -> {319}; + 319 -> {321 320}; + 320 -> {327}; + 321 -> {322}; + 322 -> {323}; + 323 -> {324}; + 324 -> {325}; + 325 -> {326}; + 326 -> {327}; + 327 -> {328}; + 328 -> {329}; + 329 -> {330}; + 330 -> {331}; + 331 -> {332}; + 332 -> {333}; + 333 -> {334}; + 334 -> {335}; + 335 -> {337 336}; + 336 -> {343}; + 337 -> {338}; + 338 -> {339}; + 339 -> {340}; + 340 -> {341}; + 341 -> {342}; + 342 -> {343}; + 343 -> {344}; + 344 -> {345}; + 345 -> {346}; + 346 -> {347}; - subgraph cluster_80 { - color=red - 346 [label="Enter function test_10" style="filled" fillcolor=red]; - subgraph cluster_81 { - color=blue - 347 [label="Enter block"]; subgraph cluster_82 { - color=blue - 348 [label="Enter when"]; + color=red + 348 [label="Enter function test_10" style="filled" fillcolor=red]; subgraph cluster_83 { color=blue - 349 [label="Enter when branch condition "]; - 350 [label="Access variable R|/a|"]; - 351 [label="Access variable R|/b|"]; - 352 [label="Equality operator =="]; - 353 [label="Exit when branch condition"]; + 349 [label="Enter block"]; + subgraph cluster_84 { + color=blue + 350 [label="Enter when"]; + subgraph cluster_85 { + color=blue + 351 [label="Enter when branch condition "]; + 352 [label="Access variable R|/a|"]; + 353 [label="Access variable R|/b|"]; + 354 [label="Equality operator =="]; + 355 [label="Exit when branch condition"]; + } + 356 [label="Synthetic else branch"]; + 357 [label="Enter when branch result"]; + subgraph cluster_86 { + color=blue + 358 [label="Enter block"]; + 359 [label="Access variable R|/b|"]; + 360 [label="Function call: R|/b|.#()"]; + 361 [label="Exit block"]; + } + 362 [label="Exit when branch result"]; + 363 [label="Exit when"]; + } + 364 [label="Access variable R|/b|"]; + 365 [label="Function call: R|/b|.#()"]; + subgraph cluster_87 { + color=blue + 366 [label="Enter when"]; + subgraph cluster_88 { + color=blue + 367 [label="Enter when branch condition "]; + 368 [label="Access variable R|/a|"]; + 369 [label="Access variable R|/b|"]; + 370 [label="Equality operator ==="]; + 371 [label="Exit when branch condition"]; + } + 372 [label="Synthetic else branch"]; + 373 [label="Enter when branch result"]; + subgraph cluster_89 { + color=blue + 374 [label="Enter block"]; + 375 [label="Access variable R|/b|"]; + 376 [label="Function call: R|/b|.#()"]; + 377 [label="Exit block"]; + } + 378 [label="Exit when branch result"]; + 379 [label="Exit when"]; + } + 380 [label="Access variable R|/b|"]; + 381 [label="Function call: R|/b|.#()"]; + subgraph cluster_90 { + color=blue + 382 [label="Enter when"]; + subgraph cluster_91 { + color=blue + 383 [label="Enter when branch condition "]; + 384 [label="Access variable R|/b|"]; + 385 [label="Access variable R|/a|"]; + 386 [label="Equality operator =="]; + 387 [label="Exit when branch condition"]; + } + 388 [label="Synthetic else branch"]; + 389 [label="Enter when branch result"]; + subgraph cluster_92 { + color=blue + 390 [label="Enter block"]; + 391 [label="Access variable R|/b|"]; + 392 [label="Function call: R|/b|.#()"]; + 393 [label="Exit block"]; + } + 394 [label="Exit when branch result"]; + 395 [label="Exit when"]; + } + 396 [label="Access variable R|/b|"]; + 397 [label="Function call: R|/b|.#()"]; + subgraph cluster_93 { + color=blue + 398 [label="Enter when"]; + subgraph cluster_94 { + color=blue + 399 [label="Enter when branch condition "]; + 400 [label="Access variable R|/b|"]; + 401 [label="Access variable R|/a|"]; + 402 [label="Equality operator ==="]; + 403 [label="Exit when branch condition"]; + } + 404 [label="Synthetic else branch"]; + 405 [label="Enter when branch result"]; + subgraph cluster_95 { + color=blue + 406 [label="Enter block"]; + 407 [label="Access variable R|/b|"]; + 408 [label="Function call: R|/b|.#()"]; + 409 [label="Exit block"]; + } + 410 [label="Exit when branch result"]; + 411 [label="Exit when"]; + } + 412 [label="Access variable R|/b|"]; + 413 [label="Function call: R|/b|.#()"]; + 414 [label="Exit block"]; } - 354 [label="Synthetic else branch"]; - 355 [label="Enter when branch result"]; - subgraph cluster_84 { - color=blue - 356 [label="Enter block"]; - 357 [label="Access variable R|/b|"]; - 358 [label="Function call: R|/b|.#()"]; - 359 [label="Exit block"]; - } - 360 [label="Exit when branch result"]; - 361 [label="Exit when"]; + 415 [label="Exit function test_10" style="filled" fillcolor=red]; } - 362 [label="Access variable R|/b|"]; - 363 [label="Function call: R|/b|.#()"]; - subgraph cluster_85 { - color=blue - 364 [label="Enter when"]; - subgraph cluster_86 { - color=blue - 365 [label="Enter when branch condition "]; - 366 [label="Access variable R|/a|"]; - 367 [label="Access variable R|/b|"]; - 368 [label="Equality operator ==="]; - 369 [label="Exit when branch condition"]; - } - 370 [label="Synthetic else branch"]; - 371 [label="Enter when branch result"]; - subgraph cluster_87 { - color=blue - 372 [label="Enter block"]; - 373 [label="Access variable R|/b|"]; - 374 [label="Function call: R|/b|.#()"]; - 375 [label="Exit block"]; - } - 376 [label="Exit when branch result"]; - 377 [label="Exit when"]; - } - 378 [label="Access variable R|/b|"]; - 379 [label="Function call: R|/b|.#()"]; - subgraph cluster_88 { - color=blue - 380 [label="Enter when"]; - subgraph cluster_89 { - color=blue - 381 [label="Enter when branch condition "]; - 382 [label="Access variable R|/b|"]; - 383 [label="Access variable R|/a|"]; - 384 [label="Equality operator =="]; - 385 [label="Exit when branch condition"]; - } - 386 [label="Synthetic else branch"]; - 387 [label="Enter when branch result"]; - subgraph cluster_90 { - color=blue - 388 [label="Enter block"]; - 389 [label="Access variable R|/b|"]; - 390 [label="Function call: R|/b|.#()"]; - 391 [label="Exit block"]; - } - 392 [label="Exit when branch result"]; - 393 [label="Exit when"]; - } - 394 [label="Access variable R|/b|"]; - 395 [label="Function call: R|/b|.#()"]; - subgraph cluster_91 { - color=blue - 396 [label="Enter when"]; - subgraph cluster_92 { - color=blue - 397 [label="Enter when branch condition "]; - 398 [label="Access variable R|/b|"]; - 399 [label="Access variable R|/a|"]; - 400 [label="Equality operator ==="]; - 401 [label="Exit when branch condition"]; - } - 402 [label="Synthetic else branch"]; - 403 [label="Enter when branch result"]; - subgraph cluster_93 { - color=blue - 404 [label="Enter block"]; - 405 [label="Access variable R|/b|"]; - 406 [label="Function call: R|/b|.#()"]; - 407 [label="Exit block"]; - } - 408 [label="Exit when branch result"]; - 409 [label="Exit when"]; - } - 410 [label="Access variable R|/b|"]; - 411 [label="Function call: R|/b|.#()"]; - 412 [label="Exit block"]; - } - 413 [label="Exit function test_10" style="filled" fillcolor=red]; - } - 346 -> {347}; - 347 -> {348}; - 348 -> {349}; - 349 -> {350}; - 350 -> {351}; - 351 -> {352}; - 352 -> {353}; - 353 -> {355 354}; - 354 -> {361}; - 355 -> {356}; - 356 -> {357}; - 357 -> {358}; - 358 -> {359}; - 359 -> {360}; - 360 -> {361}; - 361 -> {362}; - 362 -> {363}; - 363 -> {364}; - 364 -> {365}; - 365 -> {366}; - 366 -> {367}; - 367 -> {368}; - 368 -> {369}; - 369 -> {371 370}; - 370 -> {377}; - 371 -> {372}; - 372 -> {373}; - 373 -> {374}; - 374 -> {375}; - 375 -> {376}; - 376 -> {377}; - 377 -> {378}; - 378 -> {379}; - 379 -> {380}; - 380 -> {381}; - 381 -> {382}; - 382 -> {383}; - 383 -> {384}; - 384 -> {385}; - 385 -> {387 386}; - 386 -> {393}; - 387 -> {388}; - 388 -> {389}; - 389 -> {390}; - 390 -> {391}; - 391 -> {392}; - 392 -> {393}; - 393 -> {394}; - 394 -> {395}; - 395 -> {396}; - 396 -> {397}; - 397 -> {398}; - 398 -> {399}; - 399 -> {400}; - 400 -> {401}; - 401 -> {403 402}; - 402 -> {409}; - 403 -> {404}; - 404 -> {405}; - 405 -> {406}; - 406 -> {407}; - 407 -> {408}; - 408 -> {409}; - 409 -> {410}; - 410 -> {411}; - 411 -> {412}; - 412 -> {413}; + 348 -> {349}; + 349 -> {350}; + 350 -> {351}; + 351 -> {352}; + 352 -> {353}; + 353 -> {354}; + 354 -> {355}; + 355 -> {357 356}; + 356 -> {363}; + 357 -> {358}; + 358 -> {359}; + 359 -> {360}; + 360 -> {361}; + 361 -> {362}; + 362 -> {363}; + 363 -> {364}; + 364 -> {365}; + 365 -> {366}; + 366 -> {367}; + 367 -> {368}; + 368 -> {369}; + 369 -> {370}; + 370 -> {371}; + 371 -> {373 372}; + 372 -> {379}; + 373 -> {374}; + 374 -> {375}; + 375 -> {376}; + 376 -> {377}; + 377 -> {378}; + 378 -> {379}; + 379 -> {380}; + 380 -> {381}; + 381 -> {382}; + 382 -> {383}; + 383 -> {384}; + 384 -> {385}; + 385 -> {386}; + 386 -> {387}; + 387 -> {389 388}; + 388 -> {395}; + 389 -> {390}; + 390 -> {391}; + 391 -> {392}; + 392 -> {393}; + 393 -> {394}; + 394 -> {395}; + 395 -> {396}; + 396 -> {397}; + 397 -> {398}; + 398 -> {399}; + 399 -> {400}; + 400 -> {401}; + 401 -> {402}; + 402 -> {403}; + 403 -> {405 404}; + 404 -> {411}; + 405 -> {406}; + 406 -> {407}; + 407 -> {408}; + 408 -> {409}; + 409 -> {410}; + 410 -> {411}; + 411 -> {412}; + 412 -> {413}; + 413 -> {414}; + 414 -> {415}; - subgraph cluster_94 { - color=red - 414 [label="Enter function test_11" style="filled" fillcolor=red]; - subgraph cluster_95 { - color=blue - 415 [label="Enter block"]; subgraph cluster_96 { - color=blue - 416 [label="Enter when"]; + color=red + 416 [label="Enter function test_11" style="filled" fillcolor=red]; subgraph cluster_97 { color=blue - 417 [label="Enter when branch condition "]; - 418 [label="Access variable R|/q|"]; - 419 [label="Enter safe call"]; - 420 [label="Access variable R|/QImpl.data|"]; - 421 [label="Exit safe call"]; - 422 [label="Enter safe call"]; - 423 [label="Access variable R|/MyData.s|"]; - 424 [label="Exit safe call"]; - 425 [label="Enter safe call"]; - 426 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; - 427 [label="Exit safe call"]; - 428 [label="Const: Null(null)"]; - 429 [label="Equality operator !="]; - 430 [label="Exit when branch condition"]; - } - 431 [label="Synthetic else branch"]; - 432 [label="Enter when branch result"]; - subgraph cluster_98 { - color=blue - 433 [label="Enter block"]; - 434 [label="Access variable R|/q|"]; - 435 [label="Access variable R|/QImpl.data|"]; - 436 [label="Access variable R|/q|"]; - 437 [label="Access variable R|/QImpl.data|"]; - 438 [label="Access variable R|/MyData.s|"]; - 439 [label="Access variable R|/q|"]; - 440 [label="Access variable R|/QImpl.data|"]; - 441 [label="Access variable R|/MyData.s|"]; - 442 [label="Function call: R|/q|.R|/QImpl.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; - 443 [label="Access variable R|/q2|"]; - 444 [label="Access variable R|/QImpl.data|"]; - 445 [label="Access variable R|/q2|"]; - 446 [label="Access variable R|/QImpl.data|"]; - 447 [label="Access variable #"]; - 448 [label="Access variable R|/q2|"]; - 449 [label="Access variable R|/QImpl.data|"]; - 450 [label="Access variable #"]; - 451 [label="Function call: R|/q2|.R|/QImpl.data|.#.R|kotlin/Int.inc|()"]; - subgraph cluster_99 { + 417 [label="Enter block"]; + subgraph cluster_98 { color=blue - 452 [label="Enter when"]; + 418 [label="Enter when"]; + subgraph cluster_99 { + color=blue + 419 [label="Enter when branch condition "]; + 420 [label="Access variable R|/q|"]; + 421 [label="Enter safe call"]; + 422 [label="Access variable R|/QImpl.data|"]; + 423 [label="Exit safe call"]; + 424 [label="Enter safe call"]; + 425 [label="Access variable R|/MyData.s|"]; + 426 [label="Exit safe call"]; + 427 [label="Enter safe call"]; + 428 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; + 429 [label="Exit safe call"]; + 430 [label="Const: Null(null)"]; + 431 [label="Equality operator !="]; + 432 [label="Exit when branch condition"]; + } + 433 [label="Synthetic else branch"]; + 434 [label="Enter when branch result"]; subgraph cluster_100 { color=blue - 453 [label="Enter when branch condition "]; - 454 [label="Access variable R|/q2|"]; - 455 [label="Access variable R|/QImpl.data|"]; - 456 [label="Const: Null(null)"]; - 457 [label="Equality operator !="]; - 458 [label="Exit when branch condition"]; + 435 [label="Enter block"]; + 436 [label="Access variable R|/q|"]; + 437 [label="Access variable R|/QImpl.data|"]; + 438 [label="Access variable R|/q|"]; + 439 [label="Access variable R|/QImpl.data|"]; + 440 [label="Access variable R|/MyData.s|"]; + 441 [label="Access variable R|/q|"]; + 442 [label="Access variable R|/QImpl.data|"]; + 443 [label="Access variable R|/MyData.s|"]; + 444 [label="Function call: R|/q|.R|/QImpl.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; + 445 [label="Access variable R|/q2|"]; + 446 [label="Access variable R|/QImpl.data|"]; + 447 [label="Access variable R|/q2|"]; + 448 [label="Access variable R|/QImpl.data|"]; + 449 [label="Access variable #"]; + 450 [label="Access variable R|/q2|"]; + 451 [label="Access variable R|/QImpl.data|"]; + 452 [label="Access variable #"]; + 453 [label="Function call: R|/q2|.R|/QImpl.data|.#.R|kotlin/Int.inc|()"]; + subgraph cluster_101 { + color=blue + 454 [label="Enter when"]; + subgraph cluster_102 { + color=blue + 455 [label="Enter when branch condition "]; + 456 [label="Access variable R|/q2|"]; + 457 [label="Access variable R|/QImpl.data|"]; + 458 [label="Const: Null(null)"]; + 459 [label="Equality operator !="]; + 460 [label="Exit when branch condition"]; + } + 461 [label="Synthetic else branch"]; + 462 [label="Enter when branch result"]; + subgraph cluster_103 { + color=blue + 463 [label="Enter block"]; + 464 [label="Access variable R|/q2|"]; + 465 [label="Access variable R|/QImpl.data|"]; + 466 [label="Access variable R|/MyData.s|"]; + 467 [label="Access variable R|/q2|"]; + 468 [label="Access variable R|/QImpl.data|"]; + 469 [label="Access variable R|/MyData.s|"]; + 470 [label="Function call: R|/q2|.R|/QImpl.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; + 471 [label="Exit block"]; + } + 472 [label="Exit when branch result"]; + 473 [label="Exit when"]; + } + 474 [label="Exit block"]; } - 459 [label="Synthetic else branch"]; - 460 [label="Enter when branch result"]; - subgraph cluster_101 { - color=blue - 461 [label="Enter block"]; - 462 [label="Access variable R|/q2|"]; - 463 [label="Access variable R|/QImpl.data|"]; - 464 [label="Access variable R|/MyData.s|"]; - 465 [label="Access variable R|/q2|"]; - 466 [label="Access variable R|/QImpl.data|"]; - 467 [label="Access variable R|/MyData.s|"]; - 468 [label="Function call: R|/q2|.R|/QImpl.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; - 469 [label="Exit block"]; - } - 470 [label="Exit when branch result"]; - 471 [label="Exit when"]; + 475 [label="Exit when branch result"]; + 476 [label="Exit when"]; } - 472 [label="Exit block"]; + 477 [label="Exit block"]; } - 473 [label="Exit when branch result"]; - 474 [label="Exit when"]; + 478 [label="Exit function test_11" style="filled" fillcolor=red]; } - 475 [label="Exit block"]; - } - 476 [label="Exit function test_11" style="filled" fillcolor=red]; - } - 414 -> {415}; - 415 -> {416}; - 416 -> {417}; - 417 -> {418}; - 418 -> {419 421}; - 419 -> {420}; - 420 -> {421}; - 421 -> {422 424}; - 422 -> {423}; - 423 -> {424}; - 424 -> {425 427}; - 425 -> {426}; - 426 -> {427}; - 427 -> {428}; - 428 -> {429}; - 429 -> {430}; - 430 -> {432 431}; - 431 -> {474}; - 432 -> {433}; - 433 -> {434}; - 434 -> {435}; - 435 -> {436}; - 436 -> {437}; - 437 -> {438}; - 438 -> {439}; - 439 -> {440}; - 440 -> {441}; - 441 -> {442}; - 442 -> {443}; - 443 -> {444}; - 444 -> {445}; - 445 -> {446}; - 446 -> {447}; - 447 -> {448}; - 448 -> {449}; - 449 -> {450}; - 450 -> {451}; - 451 -> {452}; - 452 -> {453}; - 453 -> {454}; - 454 -> {455}; - 455 -> {456}; - 456 -> {457}; - 457 -> {458}; - 458 -> {460 459}; - 459 -> {471}; - 460 -> {461}; - 461 -> {462}; - 462 -> {463}; - 463 -> {464}; - 464 -> {465}; - 465 -> {466}; - 466 -> {467}; - 467 -> {468}; - 468 -> {469}; - 469 -> {470}; - 470 -> {471}; - 471 -> {472}; - 472 -> {473}; - 473 -> {474}; - 474 -> {475}; - 475 -> {476}; + 416 -> {417}; + 417 -> {418}; + 418 -> {419}; + 419 -> {420}; + 420 -> {421 423}; + 421 -> {422}; + 422 -> {423}; + 423 -> {424 426}; + 424 -> {425}; + 425 -> {426}; + 426 -> {427 429}; + 427 -> {428}; + 428 -> {429}; + 429 -> {430}; + 430 -> {431}; + 431 -> {432}; + 432 -> {434 433}; + 433 -> {476}; + 434 -> {435}; + 435 -> {436}; + 436 -> {437}; + 437 -> {438}; + 438 -> {439}; + 439 -> {440}; + 440 -> {441}; + 441 -> {442}; + 442 -> {443}; + 443 -> {444}; + 444 -> {445}; + 445 -> {446}; + 446 -> {447}; + 447 -> {448}; + 448 -> {449}; + 449 -> {450}; + 450 -> {451}; + 451 -> {452}; + 452 -> {453}; + 453 -> {454}; + 454 -> {455}; + 455 -> {456}; + 456 -> {457}; + 457 -> {458}; + 458 -> {459}; + 459 -> {460}; + 460 -> {462 461}; + 461 -> {473}; + 462 -> {463}; + 463 -> {464}; + 464 -> {465}; + 465 -> {466}; + 466 -> {467}; + 467 -> {468}; + 468 -> {469}; + 469 -> {470}; + 470 -> {471}; + 471 -> {472}; + 472 -> {473}; + 473 -> {474}; + 474 -> {475}; + 475 -> {476}; + 476 -> {477}; + 477 -> {478}; - subgraph cluster_102 { - color=red - 477 [label="Enter function test_12" style="filled" fillcolor=red]; - subgraph cluster_103 { - color=blue - 478 [label="Enter block"]; subgraph cluster_104 { - color=blue - 479 [label="Enter when"]; + color=red + 479 [label="Enter function test_12" style="filled" fillcolor=red]; subgraph cluster_105 { color=blue - 480 [label="Enter when branch condition "]; - 481 [label="Access variable R|/q|"]; - 482 [label="Enter safe call"]; - 483 [label="Access variable R|/QImplWithCustomGetter.data|"]; - 484 [label="Exit safe call"]; - 485 [label="Enter safe call"]; - 486 [label="Access variable R|/MyData.s|"]; - 487 [label="Exit safe call"]; - 488 [label="Enter safe call"]; - 489 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; - 490 [label="Exit safe call"]; - 491 [label="Const: Null(null)"]; - 492 [label="Equality operator !="]; - 493 [label="Exit when branch condition"]; + 480 [label="Enter block"]; + subgraph cluster_106 { + color=blue + 481 [label="Enter when"]; + subgraph cluster_107 { + color=blue + 482 [label="Enter when branch condition "]; + 483 [label="Access variable R|/q|"]; + 484 [label="Enter safe call"]; + 485 [label="Access variable R|/QImplWithCustomGetter.data|"]; + 486 [label="Exit safe call"]; + 487 [label="Enter safe call"]; + 488 [label="Access variable R|/MyData.s|"]; + 489 [label="Exit safe call"]; + 490 [label="Enter safe call"]; + 491 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; + 492 [label="Exit safe call"]; + 493 [label="Const: Null(null)"]; + 494 [label="Equality operator !="]; + 495 [label="Exit when branch condition"]; + } + 496 [label="Synthetic else branch"]; + 497 [label="Enter when branch result"]; + subgraph cluster_108 { + color=blue + 498 [label="Enter block"]; + 499 [label="Access variable R|/q|"]; + 500 [label="Access variable R|/QImplWithCustomGetter.data|"]; + 501 [label="Access variable R|/q|"]; + 502 [label="Access variable R|/QImplWithCustomGetter.data|"]; + 503 [label="Access variable #"]; + 504 [label="Access variable R|/q|"]; + 505 [label="Access variable R|/QImplWithCustomGetter.data|"]; + 506 [label="Access variable #"]; + 507 [label="Function call: R|/q|.R|/QImplWithCustomGetter.data|.#.R|kotlin/Int.inc|()"]; + 508 [label="Exit block"]; + } + 509 [label="Exit when branch result"]; + 510 [label="Exit when"]; + } + 511 [label="Exit block"]; } - 494 [label="Synthetic else branch"]; - 495 [label="Enter when branch result"]; - subgraph cluster_106 { - color=blue - 496 [label="Enter block"]; - 497 [label="Access variable R|/q|"]; - 498 [label="Access variable R|/QImplWithCustomGetter.data|"]; - 499 [label="Access variable R|/q|"]; - 500 [label="Access variable R|/QImplWithCustomGetter.data|"]; - 501 [label="Access variable #"]; - 502 [label="Access variable R|/q|"]; - 503 [label="Access variable R|/QImplWithCustomGetter.data|"]; - 504 [label="Access variable #"]; - 505 [label="Function call: R|/q|.R|/QImplWithCustomGetter.data|.#.R|kotlin/Int.inc|()"]; - 506 [label="Exit block"]; - } - 507 [label="Exit when branch result"]; - 508 [label="Exit when"]; + 512 [label="Exit function test_12" style="filled" fillcolor=red]; } - 509 [label="Exit block"]; - } - 510 [label="Exit function test_12" style="filled" fillcolor=red]; - } - 477 -> {478}; - 478 -> {479}; - 479 -> {480}; - 480 -> {481}; - 481 -> {482 484}; - 482 -> {483}; - 483 -> {484}; - 484 -> {485 487}; - 485 -> {486}; - 486 -> {487}; - 487 -> {488 490}; - 488 -> {489}; - 489 -> {490}; - 490 -> {491}; - 491 -> {492}; - 492 -> {493}; - 493 -> {495 494}; - 494 -> {508}; - 495 -> {496}; - 496 -> {497}; - 497 -> {498}; - 498 -> {499}; - 499 -> {500}; - 500 -> {501}; - 501 -> {502}; - 502 -> {503}; - 503 -> {504}; - 504 -> {505}; - 505 -> {506}; - 506 -> {507}; - 507 -> {508}; - 508 -> {509}; - 509 -> {510}; + 479 -> {480}; + 480 -> {481}; + 481 -> {482}; + 482 -> {483}; + 483 -> {484 486}; + 484 -> {485}; + 485 -> {486}; + 486 -> {487 489}; + 487 -> {488}; + 488 -> {489}; + 489 -> {490 492}; + 490 -> {491}; + 491 -> {492}; + 492 -> {493}; + 493 -> {494}; + 494 -> {495}; + 495 -> {497 496}; + 496 -> {510}; + 497 -> {498}; + 498 -> {499}; + 499 -> {500}; + 500 -> {501}; + 501 -> {502}; + 502 -> {503}; + 503 -> {504}; + 504 -> {505}; + 505 -> {506}; + 506 -> {507}; + 507 -> {508}; + 508 -> {509}; + 509 -> {510}; + 510 -> {511}; + 511 -> {512}; - subgraph cluster_107 { - color=red - 511 [label="Enter function test_13" style="filled" fillcolor=red]; - subgraph cluster_108 { - color=blue - 512 [label="Enter block"]; subgraph cluster_109 { - color=blue - 513 [label="Enter when"]; + color=red + 513 [label="Enter function test_13" style="filled" fillcolor=red]; subgraph cluster_110 { color=blue - 514 [label="Enter when branch condition "]; - 515 [label="Access variable R|/q|"]; - 516 [label="Enter safe call"]; - 517 [label="Access variable R|/QImplMutable.data|"]; - 518 [label="Exit safe call"]; - 519 [label="Enter safe call"]; - 520 [label="Access variable R|/MyData.s|"]; - 521 [label="Exit safe call"]; - 522 [label="Enter safe call"]; - 523 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; - 524 [label="Exit safe call"]; - 525 [label="Const: Null(null)"]; - 526 [label="Equality operator !="]; - 527 [label="Exit when branch condition"]; + 514 [label="Enter block"]; + subgraph cluster_111 { + color=blue + 515 [label="Enter when"]; + subgraph cluster_112 { + color=blue + 516 [label="Enter when branch condition "]; + 517 [label="Access variable R|/q|"]; + 518 [label="Enter safe call"]; + 519 [label="Access variable R|/QImplMutable.data|"]; + 520 [label="Exit safe call"]; + 521 [label="Enter safe call"]; + 522 [label="Access variable R|/MyData.s|"]; + 523 [label="Exit safe call"]; + 524 [label="Enter safe call"]; + 525 [label="Function call: $subj$.R|kotlin/Int.inc|()"]; + 526 [label="Exit safe call"]; + 527 [label="Const: Null(null)"]; + 528 [label="Equality operator !="]; + 529 [label="Exit when branch condition"]; + } + 530 [label="Synthetic else branch"]; + 531 [label="Enter when branch result"]; + subgraph cluster_113 { + color=blue + 532 [label="Enter block"]; + 533 [label="Access variable R|/q|"]; + 534 [label="Access variable R|/QImplMutable.data|"]; + 535 [label="Access variable R|/q|"]; + 536 [label="Access variable R|/QImplMutable.data|"]; + 537 [label="Access variable #"]; + 538 [label="Access variable R|/q|"]; + 539 [label="Access variable R|/QImplMutable.data|"]; + 540 [label="Access variable #"]; + 541 [label="Function call: R|/q|.R|/QImplMutable.data|.#.R|kotlin/Int.inc|()"]; + 542 [label="Exit block"]; + } + 543 [label="Exit when branch result"]; + 544 [label="Exit when"]; + } + 545 [label="Exit block"]; } - 528 [label="Synthetic else branch"]; - 529 [label="Enter when branch result"]; - subgraph cluster_111 { - color=blue - 530 [label="Enter block"]; - 531 [label="Access variable R|/q|"]; - 532 [label="Access variable R|/QImplMutable.data|"]; - 533 [label="Access variable R|/q|"]; - 534 [label="Access variable R|/QImplMutable.data|"]; - 535 [label="Access variable #"]; - 536 [label="Access variable R|/q|"]; - 537 [label="Access variable R|/QImplMutable.data|"]; - 538 [label="Access variable #"]; - 539 [label="Function call: R|/q|.R|/QImplMutable.data|.#.R|kotlin/Int.inc|()"]; - 540 [label="Exit block"]; - } - 541 [label="Exit when branch result"]; - 542 [label="Exit when"]; + 546 [label="Exit function test_13" style="filled" fillcolor=red]; } - 543 [label="Exit block"]; - } - 544 [label="Exit function test_13" style="filled" fillcolor=red]; - } - 511 -> {512}; - 512 -> {513}; - 513 -> {514}; - 514 -> {515}; - 515 -> {516 518}; - 516 -> {517}; - 517 -> {518}; - 518 -> {519 521}; - 519 -> {520}; - 520 -> {521}; - 521 -> {522 524}; - 522 -> {523}; - 523 -> {524}; - 524 -> {525}; - 525 -> {526}; - 526 -> {527}; - 527 -> {529 528}; - 528 -> {542}; - 529 -> {530}; - 530 -> {531}; - 531 -> {532}; - 532 -> {533}; - 533 -> {534}; - 534 -> {535}; - 535 -> {536}; - 536 -> {537}; - 537 -> {538}; - 538 -> {539}; - 539 -> {540}; - 540 -> {541}; - 541 -> {542}; - 542 -> {543}; - 543 -> {544}; + 513 -> {514}; + 514 -> {515}; + 515 -> {516}; + 516 -> {517}; + 517 -> {518 520}; + 518 -> {519}; + 519 -> {520}; + 520 -> {521 523}; + 521 -> {522}; + 522 -> {523}; + 523 -> {524 526}; + 524 -> {525}; + 525 -> {526}; + 526 -> {527}; + 527 -> {528}; + 528 -> {529}; + 529 -> {531 530}; + 530 -> {544}; + 531 -> {532}; + 532 -> {533}; + 533 -> {534}; + 534 -> {535}; + 535 -> {536}; + 536 -> {537}; + 537 -> {538}; + 538 -> {539}; + 539 -> {540}; + 540 -> {541}; + 541 -> {542}; + 542 -> {543}; + 543 -> {544}; + 544 -> {545}; + 545 -> {546}; -} + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.dot new file mode 100644 index 00000000000..36b0c02f339 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.dot @@ -0,0 +1,119 @@ +digraph inAnonymousObject_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Exit anonymous object"]; + 3 [label="Variable declaration: lval obj: R||"]; + 4 [label="Access variable R|/obj|"]; + 5 [label="Function call: R|/obj|.R|/.run|()"]; + 6 [label="Function call: R|/d|.R|FakeOverride|()"]; + 7 [label="Exit block"]; + } + 8 [label="Exit function foo" style="filled" fillcolor=red]; + } + subgraph cluster_2 { + color=blue + 9 [label="Enter class " style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 10 [label="Part of class initialization"]; + subgraph cluster_4 { + color=blue + 11 [label="Part of class initialization"]; + 12 [label="Exit class " style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 1 -> {13 18 16 21 23 29} [color=red]; + 2 -> {3}; + 2 -> {13 29 9} [color=green]; + 2 -> {13 29 9} [style=dashed]; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 7 -> {8}; + 9 -> {10} [color=green]; + 10 -> {11} [style=dotted]; + 10 -> {18} [color=green]; + 10 -> {18} [style=dashed]; + 11 -> {12} [style=dotted]; + 11 -> {23} [color=green]; + 11 -> {23} [style=dashed]; + + subgraph cluster_5 { + color=red + 13 [label="Enter function " style="filled" fillcolor=red]; + 14 [label="Delegated constructor call: super()"]; + 15 [label="Exit function " style="filled" fillcolor=red]; + } + 13 -> {14}; + 14 -> {15}; + + subgraph cluster_6 { + color=red + 16 [label="Enter function getter" style="filled" fillcolor=red]; + 17 [label="Exit function getter" style="filled" fillcolor=red]; + } + 16 -> {17}; + + subgraph cluster_7 { + color=red + 18 [label="Enter property" style="filled" fillcolor=red]; + 19 [label="Access variable R|/a|"]; + 20 [label="Exit property" style="filled" fillcolor=red]; + } + 18 -> {19}; + 19 -> {20}; + 20 -> {11} [color=green]; + + subgraph cluster_8 { + color=red + 21 [label="Enter function getter" style="filled" fillcolor=red]; + 22 [label="Exit function getter" style="filled" fillcolor=red]; + } + 21 -> {22}; + + subgraph cluster_9 { + color=red + 23 [label="Enter init block" style="filled" fillcolor=red]; + subgraph cluster_10 { + color=blue + 24 [label="Enter block"]; + 25 [label="Access variable R|/b|"]; + 26 [label="Assignment: R|/.leaked|"]; + 27 [label="Exit block"]; + } + 28 [label="Exit init block" style="filled" fillcolor=red]; + } + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {12} [color=green]; + + subgraph cluster_11 { + color=red + 29 [label="Enter function run" style="filled" fillcolor=red]; + subgraph cluster_12 { + color=blue + 30 [label="Enter block"]; + 31 [label="Function call: R|/c|.R|FakeOverride|()"]; + 32 [label="Exit block"]; + } + 33 [label="Exit function run" style="filled" fillcolor=red]; + } + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.kt new file mode 100644 index 00000000000..d08b5aaf341 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.kt @@ -0,0 +1,31 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun foo(a: () -> Unit, b: () -> Unit, c: () -> Unit, d: () -> Unit) { + contract { + callsInPlace(a, InvocationKind.AT_MOST_ONCE) + callsInPlace(b, InvocationKind.AT_MOST_ONCE) + callsInPlace(c, InvocationKind.AT_MOST_ONCE) + callsInPlace(d, InvocationKind.AT_MOST_ONCE) + } + + val obj = object : Runnable { + + val leakedVal = a + val leaked: Any + + init { + leaked = b + } + + override fun run() { + c() + } + + } + + obj.run() + + d() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.txt new file mode 100644 index 00000000000..8052815637e --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.txt @@ -0,0 +1,35 @@ +FILE: inAnonymousObject.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(a: R|() -> kotlin/Unit|, b: R|() -> kotlin/Unit|, c: R|() -> kotlin/Unit|, d: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(a, AT_MOST_ONCE) + CallsInPlace(b, AT_MOST_ONCE) + CallsInPlace(c, AT_MOST_ONCE) + CallsInPlace(d, AT_MOST_ONCE) + > + { + [StubStatement] + lval obj: R|| = object : R|java/lang/Runnable| { + private constructor(): R|| { + super() + } + + public final val leakedVal: R|() -> kotlin/Unit| = R|/a| + public get(): R|() -> kotlin/Unit| + + public final val leaked: R|kotlin/Any| + public get(): R|kotlin/Any| + + init { + this@R|/|.R|/.leaked| = R|/b| + } + + public final override fun run(): R|kotlin/Unit| { + R|/c|.R|FakeOverride|() + } + + } + + R|/obj|.R|/.run|() + R|/d|.R|FakeOverride|() + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.dot new file mode 100644 index 00000000000..83436eaadf4 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.dot @@ -0,0 +1,126 @@ +digraph inLocalClass_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Exit local class foo"]; + 3 [label="Function call: R|/LocalClass.LocalClass|()"]; + 4 [label="Function call: R|/LocalClass.LocalClass|().R|/LocalClass.run|()"]; + 5 [label="Function call: R|/e|.R|FakeOverride|()"]; + 6 [label="Exit block"]; + } + 7 [label="Exit function foo" style="filled" fillcolor=red]; + } + subgraph cluster_2 { + color=blue + 8 [label="Enter class LocalClass" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 9 [label="Part of class initialization"]; + subgraph cluster_4 { + color=blue + 10 [label="Part of class initialization"]; + 11 [label="Exit class LocalClass" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 1 -> {14 12 17 19 25 31} [color=red]; + 2 -> {3}; + 2 -> {19 31 8} [color=green]; + 2 -> {19 31 8} [style=dashed]; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 8 -> {9} [color=green]; + 9 -> {10} [style=dotted]; + 9 -> {14} [color=green]; + 9 -> {14} [style=dashed]; + 10 -> {11} [style=dotted]; + 10 -> {25} [color=green]; + 10 -> {25} [style=dashed]; + + subgraph cluster_5 { + color=red + 12 [label="Enter function getter" style="filled" fillcolor=red]; + 13 [label="Exit function getter" style="filled" fillcolor=red]; + } + 12 -> {13}; + + subgraph cluster_6 { + color=red + 14 [label="Enter property" style="filled" fillcolor=red]; + 15 [label="Access variable R|/a|"]; + 16 [label="Exit property" style="filled" fillcolor=red]; + } + 14 -> {15}; + 15 -> {16}; + 16 -> {10} [color=green]; + + subgraph cluster_7 { + color=red + 17 [label="Enter function getter" style="filled" fillcolor=red]; + 18 [label="Exit function getter" style="filled" fillcolor=red]; + } + 17 -> {18}; + + subgraph cluster_8 { + color=red + 19 [label="Enter function " style="filled" fillcolor=red]; + 20 [label="Delegated constructor call: super()"]; + subgraph cluster_9 { + color=blue + 21 [label="Enter block"]; + 22 [label="Function call: R|/b|.R|FakeOverride|()"]; + 23 [label="Exit block"]; + } + 24 [label="Exit function " style="filled" fillcolor=red]; + } + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + + subgraph cluster_10 { + color=red + 25 [label="Enter init block" style="filled" fillcolor=red]; + subgraph cluster_11 { + color=blue + 26 [label="Enter block"]; + 27 [label="Access variable R|/c|"]; + 28 [label="Assignment: R|/LocalClass.leaked|"]; + 29 [label="Exit block"]; + } + 30 [label="Exit init block" style="filled" fillcolor=red]; + } + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {11} [color=green]; + + subgraph cluster_12 { + color=red + 31 [label="Enter function run" style="filled" fillcolor=red]; + subgraph cluster_13 { + color=blue + 32 [label="Enter block"]; + 33 [label="Function call: R|/d|.R|FakeOverride|()"]; + 34 [label="Exit block"]; + } + 35 [label="Exit function run" style="filled" fillcolor=red]; + } + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.kt new file mode 100644 index 00000000000..8b914b7bb63 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.kt @@ -0,0 +1,35 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun foo(a: () -> Unit, b: () -> Unit, c: () -> Unit, d: () -> Unit, e: () -> Unit) { + contract { + callsInPlace(a, InvocationKind.AT_MOST_ONCE) + callsInPlace(b, InvocationKind.AT_MOST_ONCE) + callsInPlace(c, InvocationKind.AT_MOST_ONCE) + callsInPlace(d, InvocationKind.AT_MOST_ONCE) + callsInPlace(e, InvocationKind.AT_MOST_ONCE) + } + + class LocalClass { + + val leakedVal = a + val leaked: Any + + constructor() { + b() + } + + init { + leaked = c + } + + fun run() { + d() + } + } + + LocalClass().run() + + e() +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.txt new file mode 100644 index 00000000000..e84229b8218 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.txt @@ -0,0 +1,37 @@ +FILE: inLocalClass.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(a: R|() -> kotlin/Unit|, b: R|() -> kotlin/Unit|, c: R|() -> kotlin/Unit|, d: R|() -> kotlin/Unit|, e: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(a, AT_MOST_ONCE) + CallsInPlace(b, AT_MOST_ONCE) + CallsInPlace(c, AT_MOST_ONCE) + CallsInPlace(d, AT_MOST_ONCE) + CallsInPlace(e, AT_MOST_ONCE) + > + { + [StubStatement] + local final class LocalClass : R|kotlin/Any| { + public final val leakedVal: R|() -> kotlin/Unit| = R|/a| + public get(): R|() -> kotlin/Unit| + + public final val leaked: R|kotlin/Any| + public get(): R|kotlin/Any| + + public constructor(): R|LocalClass| { + super() + R|/b|.R|FakeOverride|() + } + + init { + this@R|/LocalClass|.R|/LocalClass.leaked| = R|/c| + } + + public final fun run(): R|kotlin/Unit| { + R|/d|.R|FakeOverride|() + } + + } + + R|/LocalClass.LocalClass|().R|/LocalClass.run|() + R|/e|.R|FakeOverride|() + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.dot new file mode 100644 index 00000000000..8e30780dcc7 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.dot @@ -0,0 +1,47 @@ +digraph inLocalFunction_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Local function declaration foo"]; + 3 [label="Function call: R|/localFun|()"]; + 4 [label="Function call: R|/b|.R|FakeOverride|()"]; + 5 [label="Exit block"]; + } + 6 [label="Exit function foo" style="filled" fillcolor=red]; + } + subgraph cluster_2 { + color=blue + 7 [label="Enter function localFun" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 8 [label="Enter block"]; + 9 [label="Access variable R|/a|"]; + 10 [label="Function call: R|/a|.R|FakeOverride|()"]; + 11 [label="Function call: R|/a|.R|FakeOverride|()"]; + 12 [label="Exit block"]; + } + 13 [label="Exit function localFun" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 2 -> {7} [color=red]; + 2 -> {7} [style=dashed]; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.kt new file mode 100644 index 00000000000..98b8bacb10f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.kt @@ -0,0 +1,18 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun foo(a: () -> Unit, b: () -> Unit) { + contract { + callsInPlace(a, InvocationKind.AT_MOST_ONCE) + } + + fun localFun() { + a.invoke() + a() + } + + localFun() + + b() +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.txt new file mode 100644 index 00000000000..b3d7ae3b1ae --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.txt @@ -0,0 +1,16 @@ +FILE: inLocalFunction.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(a: R|() -> kotlin/Unit|, b: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(a, AT_MOST_ONCE) + > + { + [StubStatement] + local final fun localFun(): R|kotlin/Unit| { + R|/a|.R|FakeOverride|() + R|/a|.R|FakeOverride|() + } + + R|/localFun|() + R|/b|.R|FakeOverride|() + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.dot new file mode 100644 index 00000000000..3318bfd1a0c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.dot @@ -0,0 +1,97 @@ +digraph toLocalVariables_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function bar" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Exit block"]; + } + 3 [label="Exit function bar" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + + subgraph cluster_2 { + color=red + 4 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 5 [label="Enter block"]; + subgraph cluster_4 { + color=blue + 6 [label="Enter when"]; + subgraph cluster_5 { + color=blue + 7 [label="Enter when branch condition "]; + 8 [label="Const: Boolean(true)"]; + 9 [label="Exit when branch condition"]; + } + subgraph cluster_6 { + color=blue + 10 [label="Enter when branch condition else"]; + 11 [label="Exit when branch condition"]; + } + 12 [label="Enter when branch result"]; + subgraph cluster_7 { + color=blue + 13 [label="Enter block"]; + 14 [label="Access variable R|/y|"]; + 15 [label="Variable declaration: lval yCopy: R|() -> kotlin/Unit|"]; + 16 [label="Function call: R|/yCopy|.R|FakeOverride|()"]; + 17 [label="Exit block"]; + } + 18 [label="Exit when branch result"]; + 19 [label="Enter when branch result"]; + subgraph cluster_8 { + color=blue + 20 [label="Enter block"]; + 21 [label="Access variable R|/x|"]; + 22 [label="Function call: R|/bar|(...)"]; + 23 [label="Exit block"]; + } + 24 [label="Exit when branch result"]; + 25 [label="Exit when"]; + } + 26 [label="Variable declaration: lval zCopy: R|() -> kotlin/Unit|"]; + 27 [label="Access variable R|/z|"]; + 28 [label="Assignment: R|/zCopy|"]; + 29 [label="Function call: R|/zCopy|.R|FakeOverride|()"]; + 30 [label="Exit block"]; + } + 31 [label="Exit function foo" style="filled" fillcolor=red]; + } + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {19 10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {25}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.kt new file mode 100644 index 00000000000..f8ddda10990 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.kt @@ -0,0 +1,26 @@ +// !DUMP_CFG +import kotlin.contracts.* + +fun bar(x: () -> Unit) { + +} + +@ExperimentalContracts +fun foo(x: () -> Unit, y: () -> Unit, z: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.AT_MOST_ONCE) + callsInPlace(y, InvocationKind.AT_MOST_ONCE) + callsInPlace(z, InvocationKind.AT_MOST_ONCE) + } + + if (true) { + bar(x) + } else { + val yCopy = y + yCopy() + } + + val zCopy: () -> Unit + zCopy = z + zCopy() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.txt new file mode 100644 index 00000000000..94cedab85a2 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.txt @@ -0,0 +1,26 @@ +FILE: toLocalVariables.kt + public final fun bar(x: R|() -> kotlin/Unit|): R|kotlin/Unit| { + } + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(x: R|() -> kotlin/Unit|, y: R|() -> kotlin/Unit|, z: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, AT_MOST_ONCE) + CallsInPlace(y, AT_MOST_ONCE) + CallsInPlace(z, AT_MOST_ONCE) + > + { + [StubStatement] + when () { + Boolean(true) -> { + R|/bar|(R|/x|) + } + else -> { + lval yCopy: R|() -> kotlin/Unit| = R|/y| + R|/yCopy|.R|FakeOverride|() + } + } + + lval zCopy: R|() -> kotlin/Unit| + R|/zCopy| = R|/z| + R|/zCopy|.R|FakeOverride|() + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.dot new file mode 100644 index 00000000000..b99490105ea --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.dot @@ -0,0 +1,131 @@ +digraph contractsUsage_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function bar" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Access variable R|/x|"]; + 3 [label="Function call: R|/x|.R|FakeOverride|()"]; + 4 [label="Exit block"]; + } + 5 [label="Exit function bar" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + + subgraph cluster_2 { + color=red + 6 [label="Enter function baz" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 7 [label="Enter block"]; + subgraph cluster_4 { + color=blue + 8 [label="Enter when"]; + subgraph cluster_5 { + color=blue + 9 [label="Enter when branch condition "]; + 10 [label="Const: Boolean(true)"]; + 11 [label="Exit when branch condition"]; + } + 12 [label="Synthetic else branch"]; + 13 [label="Enter when branch result"]; + subgraph cluster_6 { + color=blue + 14 [label="Enter block"]; + 15 [label="Access variable this@R|/baz|"]; + 16 [label="Function call: this@R|/baz|.R|FakeOverride|()"]; + 17 [label="Exit block"]; + } + 18 [label="Exit when branch result"]; + 19 [label="Exit when"]; + } + 20 [label="Exit block"]; + } + 21 [label="Exit function baz" style="filled" fillcolor=red]; + } + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {13 12}; + 12 -> {19}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + + subgraph cluster_7 { + color=red + 22 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_8 { + color=blue + 23 [label="Enter block"]; + subgraph cluster_9 { + color=blue + 24 [label="Enter when"]; + subgraph cluster_10 { + color=blue + 25 [label="Enter when branch condition "]; + 26 [label="Const: Boolean(true)"]; + 27 [label="Exit when branch condition"]; + } + 28 [label="Synthetic else branch"]; + 29 [label="Enter when branch result"]; + subgraph cluster_11 { + color=blue + 30 [label="Enter block"]; + 31 [label="Access variable R|/x|"]; + 32 [label="Function call: R|/x|.R|FakeOverride|()"]; + 33 [label="Access variable R|/y|"]; + 34 [label="Function call: R|/y|.R|/baz|()"]; + 35 [label="Jump: ^foo Unit"]; + 36 [label="Stub" style="filled" fillcolor=gray]; + 37 [label="Exit block" style="filled" fillcolor=gray]; + } + 38 [label="Exit when branch result" style="filled" fillcolor=gray]; + 39 [label="Exit when"]; + } + 40 [label="Access variable R|/x|"]; + 41 [label="Function call: R|/bar|(...)"]; + 42 [label="Exit block"]; + } + 43 [label="Exit function foo" style="filled" fillcolor=red]; + } + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {29 28}; + 28 -> {39}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {43}; + 35 -> {36} [style=dotted]; + 36 -> {37} [style=dotted]; + 37 -> {38} [style=dotted]; + 38 -> {39} [style=dotted]; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.kt new file mode 100644 index 00000000000..d296135048d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.kt @@ -0,0 +1,38 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun bar(x: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.EXACTLY_ONCE) + } + + x.invoke() +} + +@ExperimentalContracts +fun (() -> Unit).baz() { + contract { + callsInPlace(this@baz, InvocationKind.AT_MOST_ONCE) + } + + if(true){ + this.invoke() + } +} + +@ExperimentalContracts +fun foo(x: () -> Unit, y: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.AT_LEAST_ONCE) + callsInPlace(y, InvocationKind.AT_MOST_ONCE) + } + + if (true) { + x.invoke() + y.baz() + return + } + + bar(x) +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.txt new file mode 100644 index 00000000000..ccf03330779 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.txt @@ -0,0 +1,42 @@ +FILE: contractsUsage.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun bar(x: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, EXACTLY_ONCE) + > + { + [StubStatement] + R|/x|.R|FakeOverride|() + } + @R|kotlin/contracts/ExperimentalContracts|() public final fun R|() -> kotlin/Unit|.baz(): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(this, AT_MOST_ONCE) + > + { + [StubStatement] + when () { + Boolean(true) -> { + this@R|/baz|.R|FakeOverride|() + } + } + + } + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(x: R|() -> kotlin/Unit|, y: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, AT_LEAST_ONCE) + CallsInPlace(y, AT_MOST_ONCE) + > + { + [StubStatement] + when () { + Boolean(true) -> { + R|/x|.R|FakeOverride|() + R|/y|.R|/baz|() + ^foo Unit + } + } + + R|/bar|(R|/x|) + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.dot new file mode 100644 index 00000000000..3fc4a56ec6f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.dot @@ -0,0 +1,274 @@ +digraph flow_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function bar" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + subgraph cluster_2 { + color=blue + 2 [label="Enter when"]; + subgraph cluster_3 { + color=blue + 3 [label="Enter when branch condition "]; + 4 [label="Const: Boolean(true)"]; + 5 [label="Exit when branch condition"]; + } + 6 [label="Synthetic else branch"]; + 7 [label="Enter when branch result"]; + subgraph cluster_4 { + color=blue + 8 [label="Enter block"]; + 9 [label="Access variable R|/x|"]; + 10 [label="Function call: R|/x|.R|FakeOverride|()"]; + 11 [label="Jump: ^bar Unit"]; + 12 [label="Stub" style="filled" fillcolor=gray]; + 13 [label="Exit block" style="filled" fillcolor=gray]; + } + 14 [label="Exit when branch result" style="filled" fillcolor=gray]; + 15 [label="Exit when"]; + } + 16 [label="Access variable R|/x|"]; + 17 [label="Function call: R|/bar|(...)"]; + 18 [label="Exit block"]; + } + 19 [label="Exit function bar" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {7 6}; + 6 -> {15}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {19}; + 11 -> {12} [style=dotted]; + 12 -> {13} [style=dotted]; + 13 -> {14} [style=dotted]; + 14 -> {15} [style=dotted]; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + + subgraph cluster_5 { + color=red + 20 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_6 { + color=blue + 21 [label="Enter block"]; + subgraph cluster_7 { + color=blue + 22 [label="Enter when"]; + subgraph cluster_8 { + color=blue + 23 [label="Enter when branch condition "]; + 24 [label="Const: Boolean(true)"]; + 25 [label="Exit when branch condition"]; + } + subgraph cluster_9 { + color=blue + 26 [label="Enter when branch condition else"]; + 27 [label="Exit when branch condition"]; + } + 28 [label="Enter when branch result"]; + subgraph cluster_10 { + color=blue + 29 [label="Enter block"]; + subgraph cluster_11 { + color=blue + 30 [label="Enter when"]; + subgraph cluster_12 { + color=blue + 31 [label="Enter when branch condition "]; + 32 [label="Const: Boolean(false)"]; + 33 [label="Exit when branch condition"]; + } + subgraph cluster_13 { + color=blue + 34 [label="Enter when branch condition else"]; + 35 [label="Exit when branch condition"]; + } + 36 [label="Enter when branch result"]; + subgraph cluster_14 { + color=blue + 37 [label="Enter block"]; + 38 [label="Access variable R|/y|"]; + 39 [label="Function call: R|/y|.R|FakeOverride|()"]; + 40 [label="Access variable R|/z|"]; + 41 [label="Function call: R|/z|.R|FakeOverride|()"]; + 42 [label="Jump: ^foo Unit"]; + 43 [label="Stub" style="filled" fillcolor=gray]; + 44 [label="Exit block" style="filled" fillcolor=gray]; + } + 45 [label="Exit when branch result" style="filled" fillcolor=gray]; + 46 [label="Enter when branch result"]; + subgraph cluster_15 { + color=blue + 47 [label="Enter block"]; + 48 [label="Access variable R|/y|"]; + 49 [label="Function call: R|/y|.R|FakeOverride|()"]; + 50 [label="Exit block"]; + } + 51 [label="Exit when branch result"]; + 52 [label="Exit when"]; + } + 53 [label="Exit block"]; + } + 54 [label="Exit when branch result"]; + 55 [label="Enter when branch result"]; + subgraph cluster_16 { + color=blue + 56 [label="Enter block"]; + 57 [label="Const: Int(0)"]; + 58 [label="Const: Int(0)"]; + 59 [label="Function call: Int(0).R|kotlin/Int.rangeTo|(...)"]; + 60 [label="Function call: Int(0).R|kotlin/Int.rangeTo|(...).R|kotlin/ranges/IntProgression.iterator|()"]; + 61 [label="Variable declaration: lval : R|kotlin/collections/IntIterator|"]; + subgraph cluster_17 { + color=blue + 62 [label="Enter while loop"]; + subgraph cluster_18 { + color=blue + 63 [label="Enter loop condition"]; + 64 [label="Access variable R|/|"]; + 65 [label="Function call: R|/|.R|kotlin/collections/Iterator.hasNext|()"]; + 66 [label="Exit loop condition"]; + } + subgraph cluster_19 { + color=blue + 67 [label="Enter loop block"]; + subgraph cluster_20 { + color=blue + 68 [label="Enter block"]; + 69 [label="Access variable R|/|"]; + 70 [label="Function call: R|/|.R|kotlin/collections/IntIterator.next|()"]; + 71 [label="Variable declaration: lval i: R|kotlin/Int|"]; + 72 [label="Access variable R|/x|"]; + 73 [label="Function call: R|/x|.R|FakeOverride|()"]; + 74 [label="Exit block"]; + } + 75 [label="Exit loop block"]; + } + 76 [label="Exit whileloop"]; + } + 77 [label="Access variable R|/y|"]; + 78 [label="Function call: R|/y|.R|FakeOverride|()"]; + 79 [label="Exit block"]; + } + 80 [label="Exit when branch result"]; + 81 [label="Exit when"]; + } + subgraph cluster_21 { + color=blue + 82 [label="Enter do-while loop"]; + subgraph cluster_22 { + color=blue + 83 [label="Enter loop block"]; + subgraph cluster_23 { + color=blue + 84 [label="Enter block"]; + 85 [label="Access variable R|/z|"]; + 86 [label="Function call: R|/bar|(...)"]; + 87 [label="Exit block"]; + } + 88 [label="Exit loop block"]; + } + subgraph cluster_24 { + color=blue + 89 [label="Enter loop condition"]; + 90 [label="Const: Boolean(true)"]; + 91 [label="Exit loop condition"]; + } + 92 [label="Exit do-whileloop" style="filled" fillcolor=gray]; + } + 93 [label="Exit block" style="filled" fillcolor=gray]; + } + 94 [label="Exit function foo" style="filled" fillcolor=red]; + } + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {55 26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {46 34}; + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {94}; + 42 -> {43} [style=dotted]; + 43 -> {44} [style=dotted]; + 44 -> {45} [style=dotted]; + 45 -> {52} [style=dotted]; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {81}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {76 67}; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {63} [color=green style=dashed]; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {91}; + 91 -> {92} [style=dotted]; + 91 -> {83} [color=green style=dashed]; + 92 -> {93} [style=dotted]; + 93 -> {94} [style=dotted]; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.kt new file mode 100644 index 00000000000..e3e09278077 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.kt @@ -0,0 +1,45 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun bar(x: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.EXACTLY_ONCE) + } + + if (true) { + x.invoke() + return + } + + bar(x) +} + +@ExperimentalContracts +fun foo(x: () -> Unit, y: () -> Unit, z: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.UNKNOWN) + callsInPlace(y, InvocationKind.EXACTLY_ONCE) + callsInPlace(z, InvocationKind.AT_LEAST_ONCE) + } + + if (true) { + for (i in 0..0) { + x.invoke() + } + + y.invoke() + } else { + if (false) { + y.invoke() + } else { + y.invoke() + z.invoke() + return + } + } + + do { + bar(z) + } while (true) +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.txt new file mode 100644 index 00000000000..b5e89c4f767 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.txt @@ -0,0 +1,56 @@ +FILE: flow.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun bar(x: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, EXACTLY_ONCE) + > + { + [StubStatement] + when () { + Boolean(true) -> { + R|/x|.R|FakeOverride|() + ^bar Unit + } + } + + R|/bar|(R|/x|) + } + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(x: R|() -> kotlin/Unit|, y: R|() -> kotlin/Unit|, z: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, UNKNOWN) + CallsInPlace(y, EXACTLY_ONCE) + CallsInPlace(z, AT_LEAST_ONCE) + > + { + [StubStatement] + when () { + Boolean(true) -> { + lval : R|kotlin/collections/IntIterator| = Int(0).R|kotlin/Int.rangeTo|(Int(0)).R|kotlin/ranges/IntProgression.iterator|() + while(R|/|.R|kotlin/collections/Iterator.hasNext|()) { + lval i: R|kotlin/Int| = R|/|.R|kotlin/collections/IntIterator.next|() + R|/x|.R|FakeOverride|() + } + + R|/y|.R|FakeOverride|() + } + else -> { + when () { + Boolean(false) -> { + R|/y|.R|FakeOverride|() + } + else -> { + R|/y|.R|FakeOverride|() + R|/z|.R|FakeOverride|() + ^foo Unit + } + } + + } + } + + do { + R|/bar|(R|/z|) + } + while(Boolean(true)) + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.dot new file mode 100644 index 00000000000..d43bfb9c90f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.dot @@ -0,0 +1,91 @@ +digraph inPlaceLambda_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function bar" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + subgraph cluster_2 { + color=blue + 2 [label="Enter when"]; + subgraph cluster_3 { + color=blue + 3 [label="Enter when branch condition "]; + 4 [label="Const: Boolean(true)"]; + 5 [label="Exit when branch condition"]; + } + 6 [label="Synthetic else branch"]; + 7 [label="Enter when branch result"]; + subgraph cluster_4 { + color=blue + 8 [label="Enter block"]; + 9 [label="Function call: R|/x|.R|FakeOverride|()"]; + 10 [label="Exit block"]; + } + 11 [label="Exit when branch result"]; + 12 [label="Exit when"]; + } + 13 [label="Exit block"]; + } + 14 [label="Exit function bar" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {7 6}; + 6 -> {12}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + + subgraph cluster_5 { + color=red + 15 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_6 { + color=blue + 16 [label="Enter block"]; + 17 [label="Function call: R|/x|.R|FakeOverride|()"]; + 18 [label="Postponed enter to lambda"]; + subgraph cluster_7 { + color=blue + 23 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_8 { + color=blue + 24 [label="Enter block"]; + 25 [label="Function call: R|/x|.R|FakeOverride|()"]; + 26 [label="Exit block"]; + } + 27 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 19 [label="Postponed exit from lambda"]; + 20 [label="Function call: R|/bar|(...)"]; + 21 [label="Exit block"]; + } + 22 [label="Exit function foo" style="filled" fillcolor=red]; + } + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {23}; + 18 -> {19} [color=red]; + 18 -> {23} [style=dashed]; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 23 -> {27 24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {19} [color=green]; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.kt new file mode 100644 index 00000000000..76070c5730c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.kt @@ -0,0 +1,26 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun bar(x: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.AT_MOST_ONCE) + } + + if (true) { + x() + } +} + +@ExperimentalContracts +fun foo(x: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.AT_LEAST_ONCE) + } + + x() + + bar { + x() + } +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.txt new file mode 100644 index 00000000000..202bb77399b --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.txt @@ -0,0 +1,28 @@ +FILE: inPlaceLambda.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun bar(x: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, AT_MOST_ONCE) + > + { + [StubStatement] + when () { + Boolean(true) -> { + R|/x|.R|FakeOverride|() + } + } + + } + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, AT_LEAST_ONCE) + > + { + [StubStatement] + R|/x|.R|FakeOverride|() + R|/bar|( = bar@fun (): R|kotlin/Unit| { + R|/x|.R|FakeOverride|() + } + ) + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.dot new file mode 100644 index 00000000000..c9929329de1 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.dot @@ -0,0 +1,77 @@ +digraph simple_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function bar" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Access variable R|/x|"]; + 3 [label="Function call: R|/x|.R|FakeOverride|()"]; + 4 [label="Exit block"]; + } + 5 [label="Exit function bar" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + + subgraph cluster_2 { + color=red + 6 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 7 [label="Enter block"]; + 8 [label="Access variable R|/x|"]; + 9 [label="Function call: R|/x|.R|FakeOverride|()"]; + subgraph cluster_4 { + color=blue + 10 [label="Enter when"]; + subgraph cluster_5 { + color=blue + 11 [label="Enter when branch condition "]; + 12 [label="Const: Boolean(true)"]; + 13 [label="Exit when branch condition"]; + } + 14 [label="Synthetic else branch"]; + 15 [label="Enter when branch result"]; + subgraph cluster_6 { + color=blue + 16 [label="Enter block"]; + 17 [label="Function call: R|/y|.R|FakeOverride|()"]; + 18 [label="Exit block"]; + } + 19 [label="Exit when branch result"]; + 20 [label="Exit when"]; + } + 21 [label="Access variable R|/z|"]; + 22 [label="Function call: R|/bar|(...)"]; + 23 [label="Exit block"]; + } + 24 [label="Exit function foo" style="filled" fillcolor=red]; + } + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + 13 -> {15 14}; + 14 -> {20}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.kt new file mode 100644 index 00000000000..8ef28dcb9d7 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.kt @@ -0,0 +1,28 @@ +// !DUMP_CFG +import kotlin.contracts.* + +@ExperimentalContracts +fun bar(x: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.EXACTLY_ONCE) + } + + x.invoke() +} + +@ExperimentalContracts +fun foo(x: () -> Unit, y: () -> Unit, z: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.EXACTLY_ONCE) + callsInPlace(y, InvocationKind.AT_MOST_ONCE) + callsInPlace(z, InvocationKind.EXACTLY_ONCE) + } + + x.invoke() + + if (true) { + y() + } + + bar(z) +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.txt new file mode 100644 index 00000000000..7e2313cfffd --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.txt @@ -0,0 +1,28 @@ +FILE: simple.kt + @R|kotlin/contracts/ExperimentalContracts|() public final fun bar(x: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, EXACTLY_ONCE) + > + { + [StubStatement] + R|/x|.R|FakeOverride|() + } + @R|kotlin/contracts/ExperimentalContracts|() public final fun foo(x: R|() -> kotlin/Unit|, y: R|() -> kotlin/Unit|, z: R|() -> kotlin/Unit|): R|kotlin/Unit| + [R|Contract description] + < + CallsInPlace(x, EXACTLY_ONCE) + CallsInPlace(y, AT_MOST_ONCE) + CallsInPlace(z, EXACTLY_ONCE) + > + { + [StubStatement] + R|/x|.R|FakeOverride|() + when () { + Boolean(true) -> { + R|/y|.R|FakeOverride|() + } + } + + R|/bar|(R|/z|) + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/initialization/fromLocalMembers.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/initialization/fromLocalMembers.txt index 57285c8f132..d31bec2a3f0 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/initialization/fromLocalMembers.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/initialization/fromLocalMembers.txt @@ -11,7 +11,7 @@ FILE: fromLocalMembers.kt lval x: R|kotlin/Int| lval y: R|kotlin/Int| object : R|kotlin/Any| { - private[local] constructor(): R|| { + private constructor(): R|| { super() } @@ -19,7 +19,7 @@ FILE: fromLocalMembers.kt R|/x| = Int(0) } - public[local] final fun localFunc(): R|kotlin/Unit| { + public final fun localFunc(): R|kotlin/Unit| { R|/y| = Int(0) } @@ -32,7 +32,7 @@ FILE: fromLocalMembers.kt lval x: R|kotlin/Int| lval y: R|kotlin/Int| local final class A : R|kotlin/Any| { - public[local] constructor(): R|A| { + public constructor(): R|A| { super() } @@ -40,7 +40,7 @@ FILE: fromLocalMembers.kt R|/x| = Int(0) } - public[local] final fun localFunc(): R|kotlin/Unit| { + public final fun localFunc(): R|kotlin/Unit| { R|/y| = Int(0) } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 1c9fa286ac6..906b8dd3030 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -546,6 +546,52 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } + @TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Bad extends AbstractFirDiagnosticsWithStdlibTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInBad() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CallsInPlace extends AbstractFirDiagnosticsWithStdlibTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCallsInPlace() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("inAnonymousObject.kt") + public void testInAnonymousObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inAnonymousObject.kt"); + } + + @TestMetadata("inLocalClass.kt") + public void testInLocalClass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalClass.kt"); + } + + @TestMetadata("inLocalFunction.kt") + public void testInLocalFunction() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/inLocalFunction.kt"); + } + + @TestMetadata("toLocalVariables.kt") + public void testToLocalVariables() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/bad/callsInPlace/toLocalVariables.kt"); + } + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -580,11 +626,31 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/atMostOnce.kt"); } + @TestMetadata("contractsUsage.kt") + public void testContractsUsage() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/contractsUsage.kt"); + } + @TestMetadata("exactlyOnce.kt") public void testExactlyOnce() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/exactlyOnce.kt"); } + @TestMetadata("flow.kt") + public void testFlow() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/flow.kt"); + } + + @TestMetadata("inPlaceLambda.kt") + public void testInPlaceLambda() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/inPlaceLambda.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/simple.kt"); + } + @TestMetadata("unknown.kt") public void testUnknown() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/unknown.kt"); diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt new file mode 100644 index 00000000000..8e39373505f --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt @@ -0,0 +1,310 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.cfa + +import kotlinx.collections.immutable.PersistentMap +import kotlinx.collections.immutable.persistentMapOf +import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.contracts.FirContractDescription +import org.jetbrains.kotlin.fir.contracts.description.ConeCallsEffectDeclaration +import org.jetbrains.kotlin.fir.contracts.effects +import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction +import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner +import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess +import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList +import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol +import org.jetbrains.kotlin.fir.references.FirReference +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.references.FirThisReference +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.* +import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType +import org.jetbrains.kotlin.fir.resolve.isInvoke +import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.coneTypeSafe +import org.jetbrains.kotlin.utils.addIfNotNull +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +object FirCallsEffectAnalyzer : FirControlFlowChecker() { + + override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter) { + val function = (graph.declaration as? FirFunction<*>) ?: return + if (function !is FirContractDescriptionOwner) return + if (function.contractDescription.effects?.any { it is ConeCallsEffectDeclaration } != true) return + + val functionalTypeEffects = mutableMapOf, ConeCallsEffectDeclaration>() + + function.valueParameters.forEachIndexed { index, parameter -> + if (parameter.returnTypeRef.isFunctionalTypeRef(function.session)) { + val effectDeclaration = function.contractDescription.getParameterCallsEffectDeclaration(index) + if (effectDeclaration != null) functionalTypeEffects[parameter.symbol] = effectDeclaration + } + } + + if (function.receiverTypeRef.isFunctionalTypeRef(function.session)) { + val effectDeclaration = function.contractDescription.getParameterCallsEffectDeclaration(-1) + if (effectDeclaration != null) functionalTypeEffects[function.symbol] = effectDeclaration + } + + if (functionalTypeEffects.isEmpty()) return + + val leakedSymbols = mutableMapOf, MutableList>() + graph.traverse( + TraverseDirection.Forward, + CapturedLambdaFinder(function), + IllegalScopeContext(functionalTypeEffects.keys, leakedSymbols) + ) + + for ((symbol, leakedPlaces) in leakedSymbols) { + function.contractDescription.source?.let { + reporter.report(FirErrors.LEAKED_IN_PLACE_LAMBDA.on(it, symbol)) + } + leakedPlaces.forEach { + reporter.report(FirErrors.LEAKED_IN_PLACE_LAMBDA.on(it, symbol)) + } + } + + val invocationData = graph.collectDataForNode( + TraverseDirection.Forward, + LambdaInvocationInfo.EMPTY, + InvocationDataCollector(functionalTypeEffects.keys.filterTo(mutableSetOf()) { it !in leakedSymbols }) + ) + + for ((symbol, effectDeclaration) in functionalTypeEffects) { + graph.exitNode.previousCfgNodes.forEach { node -> + val requiredRange = effectDeclaration.kind + val foundRange = invocationData.getValue(node)[symbol] ?: EventOccurrencesRange.ZERO + + if (foundRange !in requiredRange) { + function.contractDescription.source?.let { + reporter.report(FirErrors.WRONG_INVOCATION_KIND.on(it, symbol, requiredRange, foundRange)) + } + } + } + } + } + + private class IllegalScopeContext( + private val functionalTypeSymbols: Set>, + private val leakedSymbols: MutableMap, MutableList>, + ) { + private var scopeDepth: Int = 0 + private var illegalScopeDepth: Int? = null + + val inIllegalScope: Boolean get() = illegalScopeDepth != null + + fun enterScope(legal: Boolean) { + scopeDepth++ + if (illegalScopeDepth == null && !legal) illegalScopeDepth = scopeDepth + } + + fun exitScope() { + if (scopeDepth == illegalScopeDepth) illegalScopeDepth = null + scopeDepth-- + } + + inline fun checkExpressionForLeakedSymbols( + fir: FirExpression?, + source: FirSourceElement? = fir?.source, + illegalUsage: () -> Boolean = { false } + ) { + val symbol = referenceToSymbol(fir.toQualifiedReference()) + if (symbol != null && symbol in functionalTypeSymbols && (inIllegalScope || illegalUsage())) { + leakedSymbols.getOrPut(symbol, ::mutableListOf).addIfNotNull(source) + } + } + } + + private class CapturedLambdaFinder(val rootFunction: FirFunction<*>) : ControlFlowGraphVisitor() { + + override fun visitNode(node: CFGNode<*>, data: IllegalScopeContext) {} + + override fun visitFunctionEnterNode(node: FunctionEnterNode, data: IllegalScopeContext) { + data.enterScope(node.fir === rootFunction || node.fir.isInPlaceLambda()) + } + + override fun visitFunctionExitNode(node: FunctionExitNode, data: IllegalScopeContext) { + data.exitScope() + } + + override fun visitPropertyInitializerEnterNode(node: PropertyInitializerEnterNode, data: IllegalScopeContext) { + data.enterScope(false) + data.checkExpressionForLeakedSymbols(node.fir.initializer) + } + + override fun visitPropertyInitializerExitNode(node: PropertyInitializerExitNode, data: IllegalScopeContext) { + data.exitScope() + } + + override fun visitInitBlockEnterNode(node: InitBlockEnterNode, data: IllegalScopeContext) { + data.enterScope(false) + } + + override fun visitInitBlockExitNode(node: InitBlockExitNode, data: IllegalScopeContext) { + data.exitScope() + } + + override fun visitVariableAssignmentNode(node: VariableAssignmentNode, data: IllegalScopeContext) { + data.checkExpressionForLeakedSymbols(node.fir.rValue) { true } + } + + override fun visitVariableDeclarationNode(node: VariableDeclarationNode, data: IllegalScopeContext) { + data.checkExpressionForLeakedSymbols(node.fir.initializer) { true } + } + + override fun visitFunctionCallNode(node: FunctionCallNode, data: IllegalScopeContext) { + val functionSymbol = node.fir.toResolvedCallableSymbol() as? FirFunctionSymbol<*>? + val contractDescription = functionSymbol?.fir?.contractDescription + + val callSource = node.fir.explicitReceiver?.source ?: node.fir.source + data.checkExpressionForLeakedSymbols(node.fir.explicitReceiver, callSource) { + functionSymbol?.callableId?.isInvoke() != true && contractDescription?.getParameterCallsEffect(-1) == null + } + + for (arg in node.fir.argumentList.arguments) { + data.checkExpressionForLeakedSymbols(arg) { + node.fir.getArgumentCallsEffect(arg) == null + } + } + } + } + + private class LambdaInvocationInfo( + map: PersistentMap, EventOccurrencesRange> = persistentMapOf(), + ) : ControlFlowInfo, EventOccurrencesRange>(map) { + + companion object { + val EMPTY = LambdaInvocationInfo() + } + + override val constructor: (PersistentMap, EventOccurrencesRange>) -> LambdaInvocationInfo = + ::LambdaInvocationInfo + + fun merge(other: LambdaInvocationInfo): LambdaInvocationInfo { + var result = this + for (symbol in keys.union(other.keys)) { + val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO + val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO + result = result.put(symbol, kind1 or kind2) + } + return result + } + } + + private class InvocationDataCollector( + val functionalTypeSymbols: Set> + ) : ControlFlowGraphVisitor>() { + + override fun visitNode(node: CFGNode<*>, data: Collection): LambdaInvocationInfo { + if (data.isEmpty()) return LambdaInvocationInfo.EMPTY + return data.reduce(LambdaInvocationInfo::merge) + } + + override fun visitFunctionCallNode( + node: FunctionCallNode, + data: Collection + ): LambdaInvocationInfo { + var dataForNode = visitNode(node, data) + + val functionSymbol = node.fir.toResolvedCallableSymbol() as? FirFunctionSymbol<*>? + val contractDescription = functionSymbol?.fir?.contractDescription + + dataForNode = dataForNode.checkReference(node.fir.explicitReceiver.toQualifiedReference()) { + when { + functionSymbol?.callableId?.isInvoke() == true -> EventOccurrencesRange.EXACTLY_ONCE + else -> contractDescription.getParameterCallsEffect(-1) ?: EventOccurrencesRange.UNKNOWN + } + } + + for (arg in node.fir.argumentList.arguments) { + dataForNode = dataForNode.checkReference(arg.toQualifiedReference()) { + node.fir.getArgumentCallsEffect(arg) ?: EventOccurrencesRange.ZERO + } + } + + return dataForNode + } + + @OptIn(ExperimentalContracts::class) + private fun collectDataForReference(reference: FirReference?): Boolean { + contract { + returns(true) implies (reference != null) + } + return reference != null && referenceToSymbol(reference) in functionalTypeSymbols + } + + private inline fun LambdaInvocationInfo.checkReference( + reference: FirReference?, + rangeGetter: () -> EventOccurrencesRange + ): LambdaInvocationInfo { + return if (collectDataForReference(reference)) addInvocationInfo(reference, rangeGetter()) else this + } + + private fun LambdaInvocationInfo.addInvocationInfo( + reference: FirReference, + range: EventOccurrencesRange + ): LambdaInvocationInfo { + val symbol = referenceToSymbol(reference) + return if (symbol != null) { + val existingKind = this[symbol] ?: EventOccurrencesRange.ZERO + val kind = existingKind + range + this.put(symbol, kind) + } else this + } + } + + private fun FirTypeRef?.isFunctionalTypeRef(session: FirSession): Boolean { + return this?.coneTypeSafe()?.isBuiltinFunctionalType(session) == true + } + + private val FirFunction<*>.contractDescription: FirContractDescription? + get() = (this as? FirContractDescriptionOwner)?.contractDescription + + private fun FirContractDescription?.getParameterCallsEffectDeclaration(index: Int): ConeCallsEffectDeclaration? { + val effects = this?.effects + val callsEffect = effects?.find { it is ConeCallsEffectDeclaration && it.valueParameterReference.parameterIndex == index } + return callsEffect as? ConeCallsEffectDeclaration? + } + + private fun FirFunctionCall.getArgumentCallsEffect(arg: FirExpression): EventOccurrencesRange? { + val function = (this.toResolvedCallableSymbol() as? FirFunctionSymbol<*>?)?.fir + val contractDescription = function?.contractDescription + val resolvedArguments = argumentList as? FirResolvedArgumentList + + return if (function != null && resolvedArguments != null) { + val parameter = resolvedArguments.mapping[arg] + contractDescription.getParameterCallsEffect(function.valueParameters.indexOf(parameter)) + } else null + } + + private fun FirContractDescription?.getParameterCallsEffect(index: Int): EventOccurrencesRange? { + return getParameterCallsEffectDeclaration(index)?.kind + } + + private fun FirFunction<*>.isInPlaceLambda(): Boolean { + return this is FirAnonymousFunction && this.isLambda && this.invocationKind != null + } + + private fun FirExpression?.toQualifiedReference(): FirReference? = (this as? FirQualifiedAccess)?.calleeReference + + private fun referenceToSymbol(reference: FirReference?): AbstractFirBasedSymbol<*>? = when (reference) { + is FirResolvedNamedReference -> reference.resolvedSymbol + is FirThisReference -> reference.boundSymbol + else -> null + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt index 8909110eb20..835dac35f0f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.fir.analysis.cfa.FirCallsEffectAnalyzer import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker @@ -40,6 +41,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { ) override val controlFlowAnalyserCheckers: List = listOf( - FirPropertyInitializationAnalyzer + FirPropertyInitializationAnalyzer, + FirCallsEffectAnalyzer ) } \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 7f6d459c467..935718cc5f6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFI import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_MODIFIERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_INTERFACE_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_OBJECT_NOT_ALLOWED @@ -85,6 +86,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_EXPECTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS @Suppress("unused") @@ -132,7 +134,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(RECURSION_IN_SUPERTYPES, "Recursion in supertypes") map.put(NOT_A_SUPERTYPE, "Not an immediate supertype") map.put(SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE, "Superclass is not accessible from interface") - map.put(QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE, "Explicitly qualified supertype is extended by another supertype ''{0}''", TO_STRING) + map.put( + QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE, + "Explicitly qualified supertype is extended by another supertype ''{0}''", + TO_STRING + ) // Constructor problems map.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects") @@ -144,11 +150,17 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, "Supertype initialization is impossible without primary constructor") map.put(DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, "Call to super is not allowed in enum constructor") map.put(PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS, "Primary constructor required for data class") - map.put(EXPLICIT_DELEGATION_CALL_REQUIRED, "Explicit 'this' or 'super' call is required. There is no constructor in superclass that can be called without arguments") + map.put( + EXPLICIT_DELEGATION_CALL_REQUIRED, + "Explicit 'this' or 'super' call is required. There is no constructor in superclass that can be called without arguments" + ) // Annotations map.put(ANNOTATION_CLASS_MEMBER, "Members are not allowed in annotation class") - map.put(ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT, "Default value of annotation parameter must be a compile-time constant") + map.put( + ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT, + "Default value of annotation parameter must be a compile-time constant" + ) map.put(LOCAL_ANNOTATION_CLASS_ERROR, "Annotation class cannot be local") map.put(MISSING_VAL_ON_ANNOTATION_PARAMETER, "'val' keyword is missing on annotation parameter") map.put(NULLABLE_TYPE_OF_ANNOTATION_MEMBER, "An annotation parameter cannot be nullable") @@ -157,14 +169,32 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(NOT_AN_ANNOTATION_CLASS, "Illegal annotation class: {0}", NULLABLE_STRING) // Exposed visibility group // # - map.put(EXPOSED_TYPEALIAS_EXPANDED_TYPE, "{0} typealias exposes {2} in expanded type ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) - map.put(EXPOSED_FUNCTION_RETURN_TYPE, "{0} function exposes its {2} return type ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) + map.put( + EXPOSED_TYPEALIAS_EXPANDED_TYPE, + "{0} typealias exposes {2} in expanded type ''{1}''", + TO_STRING, + DECLARATION_NAME, + TO_STRING + ) + map.put( + EXPOSED_FUNCTION_RETURN_TYPE, + "{0} function exposes its {2} return type ''{1}''", + TO_STRING, + DECLARATION_NAME, + TO_STRING + ) map.put(EXPOSED_RECEIVER_TYPE, "{0} member exposes its {2} receiver type ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) map.put(EXPOSED_PROPERTY_TYPE, "{0} property exposes its {2} type ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) map.put(EXPOSED_PARAMETER_TYPE, "{0} function exposes its {2} parameter type ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) map.put(EXPOSED_SUPER_INTERFACE, "{0} sub-interface exposes its {2} supertype ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) map.put(EXPOSED_SUPER_CLASS, "{0} subclass exposes its {2} supertype ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) - map.put(EXPOSED_TYPE_PARAMETER_BOUND, "{0} generic exposes its {2} parameter bound type ''{1}''", TO_STRING, DECLARATION_NAME, TO_STRING) + map.put( + EXPOSED_TYPE_PARAMETER_BOUND, + "{0} generic exposes its {2} parameter bound type ''{1}''", + TO_STRING, + DECLARATION_NAME, + TO_STRING + ) // Modifiers map.put(INAPPLICABLE_INFIX_MODIFIER, "''infix'' modifier is inapplicable on this function: {0}", TO_STRING) @@ -188,7 +218,12 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties") map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", TO_STRING, TO_STRING) map.put(TYPE_ARGUMENTS_NOT_ALLOWED, "Type arguments are not allowed for type parameters") // * - map.put(WRONG_NUMBER_OF_TYPE_ARGUMENTS, "{0,choice,0#No type arguments|1#One type argument|1<{0,number,integer} type arguments} expected for {1}", null, TO_STRING) + map.put( + WRONG_NUMBER_OF_TYPE_ARGUMENTS, + "{0,choice,0#No type arguments|1#One type argument|1<{0,number,integer} type arguments} expected for {1}", + null, + TO_STRING + ) map.put(NO_TYPE_FOR_TYPE_PARAMETER, "There're no types suitable for this type parameter") // & map.put(TYPE_PARAMETERS_IN_OBJECT, "Type parameters are not allowed for objects") // map.put(ILLEGAL_PROJECTION_USAGE, ...) // & @@ -199,11 +234,28 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(REDECLARATION, "Conflicting declarations: {0}", TO_STRING) // * // Invalid local declarations - map.put(LOCAL_OBJECT_NOT_ALLOWED, "Named object ''{0}'' is a singleton and cannot be local. Try to use anonymous object instead", TO_STRING) // + - map.put(LOCAL_INTERFACE_NOT_ALLOWED, "''{0}'' is an interface so it cannot be local. Try to use anonymous object or abstract class instead", TO_STRING) + map.put( + LOCAL_OBJECT_NOT_ALLOWED, + "Named object ''{0}'' is a singleton and cannot be local. Try to use anonymous object instead", + TO_STRING + ) // + + map.put( + LOCAL_INTERFACE_NOT_ALLOWED, + "''{0}'' is an interface so it cannot be local. Try to use anonymous object or abstract class instead", + TO_STRING + ) // Control flow diagnostics map.put(UNINITIALIZED_VARIABLE, "{0} must be initialized before access", PROPERTY_NAME) + map.put( + WRONG_INVOCATION_KIND, + "{2} wrong invocation kind: given {3} case, but {4} case is possible", + SYMBOL, + TO_STRING, + TO_STRING + ) + map.put(LEAKED_IN_PLACE_LAMBDA, "Leaked in-place lambda: {2}", SYMBOL) + // Extended checkers group // map.put(REDUNDANT_VISIBILITY_MODIFIER, ...) // & diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index daf6aabef6e..add5b0dc090 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -7,12 +7,14 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics import com.intellij.psi.PsiElement import com.intellij.psi.PsiTypeElement +import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.fir.FirEffectiveVisibility import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol @@ -127,6 +129,8 @@ object FirErrors { // Control flow diagnostics val UNINITIALIZED_VARIABLE by error1() + val WRONG_INVOCATION_KIND by warning3, EventOccurrencesRange, EventOccurrencesRange>() + val LEAKED_IN_PLACE_LAMBDA by error1>() // Extended checkers group val REDUNDANT_VISIBILITY_MODIFIER by warning0() diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/EventOccurrencesRange.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/EventOccurrencesRange.kt index c13eaffc863..0997a0d4969 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/EventOccurrencesRange.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/EventOccurrencesRange.kt @@ -38,6 +38,7 @@ enum class EventOccurrencesRange(private val left: Int, private val right: Int) infix fun or(other: EventOccurrencesRange): EventOccurrencesRange = Companion.or(this, other) operator fun plus(other: EventOccurrencesRange): EventOccurrencesRange = Companion.plus(this, other) + operator fun contains(other: EventOccurrencesRange): Boolean = left <= other.left && other.right <= right } fun EventOccurrencesRange.isDefinitelyVisited(): Boolean = this == EventOccurrencesRange.EXACTLY_ONCE || this == EventOccurrencesRange.AT_LEAST_ONCE || this == EventOccurrencesRange.MORE_THAN_ONCE diff --git a/compiler/testData/diagnostics/tests/smartCasts/kt32358_2.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/kt32358_2.fir.kt index c185e3cae6e..ed37dc9ad77 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/kt32358_2.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/kt32358_2.fir.kt @@ -6,9 +6,9 @@ import kotlin.contracts.* inline fun callIt(fn: () -> R): R = TODO() inline fun callItContracted(fn: () -> R): R { - contract { + contract { callsInPlace(fn, InvocationKind.EXACTLY_ONCE) - } + } TODO() } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.fir.kt new file mode 100644 index 00000000000..6aa722fab9e --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.fir.kt @@ -0,0 +1,25 @@ +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts + + +// FILE: contracts.kt + +package contracts + +import kotlin.contracts.* + +// TESTCASE NUMBER: 1 +fun case_1(x: Double = 1.0, block: () -> Unit): Double { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return x +} + +// FILE: main.kt + +import contracts.* + +// TESTCASE NUMBER: 1 +fun case_1() { + val value_1: Int + contracts.case_1 { value_1 = 10 } + value_1.inc() +} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.kt index 5fa12d9e3de..6b453b66fb7 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/pos/5.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts /* diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/pos/7.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/pos/7.fir.kt index 21452b908e5..1491caa497e 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/pos/7.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/pos/7.fir.kt @@ -8,7 +8,7 @@ import kotlin.contracts.* // TESTCASE NUMBER: 1 fun case_1(x: Double = 1.0, block: () -> Unit): Double { - contract { callsInPlace(block, InvocationKind.AT_LEAST_ONCE) } + contract { callsInPlace(block, InvocationKind.AT_LEAST_ONCE) } return x } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/1.fir.kt index a2918b15657..7fefbf338fa 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/1.fir.kt @@ -4,7 +4,7 @@ import kotlin.contracts.* // TESTCASE NUMBER: 1 inline fun case_1(block: () -> Unit) { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() case_1(block) } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/4.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/4.fir.kt index 299546209ef..be52cf50838 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/4.fir.kt @@ -27,9 +27,9 @@ var Boolean.case_3: () -> Unit return {} } set(value) { - contract { + contract { callsInPlace(value, InvocationKind.EXACTLY_ONCE) - } + } } // TESTCASE NUMBER: 4