From 200c13baf54457ebfc97eac179456180fe4e3708 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Fri, 23 Aug 2019 13:31:07 +0300 Subject: [PATCH] [FIR] Add tests for smartcasts --- .../smartcasts/booleanOperators.cfg.dot | 249 ++++++ .../resolve/smartcasts/booleanOperators.kt | 40 + .../resolve/smartcasts/booleanOperators.txt | 58 ++ .../testData/resolve/smartcasts/casts.cfg.dot | 310 +++++++ .../testData/resolve/smartcasts/casts.kt | 44 + .../testData/resolve/smartcasts/casts.txt | 67 ++ .../smartcasts/equalsAndIdentity.cfg.dot | 305 +++++++ .../resolve/smartcasts/equalsAndIdentity.kt | 37 + .../resolve/smartcasts/equalsAndIdentity.txt | 73 ++ .../resolve/smartcasts/nullability.cfg.dot | 831 ++++++++++++++++++ .../resolve/smartcasts/nullability.kt | 119 +++ .../resolve/smartcasts/nullability.txt | 192 ++++ .../resolve/smartcasts/returns.cfg.dot | 273 ++++++ .../testData/resolve/smartcasts/returns.kt | 50 ++ .../testData/resolve/smartcasts/returns.txt | 69 ++ .../resolve/smartcasts/simpleIf.cfg.dot | 161 ++++ .../testData/resolve/smartcasts/simpleIf.kt | 25 + .../testData/resolve/smartcasts/simpleIf.txt | 37 + .../fir/FirCfgBuildingTestGenerated.java | 134 ++- .../fir/FirResolveTestCaseGenerated.java | 2 +- .../generators/tests/GenerateCompilerTests.kt | 3 +- 21 files changed, 3033 insertions(+), 46 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.txt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/casts.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/casts.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/casts.txt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.txt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/nullability.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/nullability.txt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/returns.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/returns.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/returns.txt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.txt diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.cfg.dot new file mode 100644 index 00000000000..c9947b062a2 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.cfg.dot @@ -0,0 +1,249 @@ +digraph booleanOperators_kt { +subgraph foo { + 0 [shape=box label="Enter function foo"]; + 1 [shape=box label="Exit function foo"]; + + 0 -> {1}; +} + +subgraph bar { + 2 [shape=box label="Enter function bar"]; + 3 [shape=box label="Exit function bar"]; + + 2 -> {3}; +} + +subgraph baz { + 4 [shape=box label="Enter function baz"]; + 5 [shape=box label="Exit function baz"]; + + 4 -> {5}; +} + +subgraph test_1 { + 6 [shape=box label="Enter function test_1"]; + 7 [shape=box label="Enter block"]; + 8 [shape=box label="Enter when"]; + 9 [shape=box label="Enter when branch condition "]; + 10 [shape=box label="Enter &&"]; + 11 [shape=box label="Access variable R|/x|"]; + 12 [shape=box label="Type operator: x is B"]; + 13 [shape=box label="Access variable R|/x|"]; + 14 [shape=box label="Type operator: x is C"]; + 15 [shape=box label="Exit &&"]; + 16 [shape=box label="Exit when branch condition"]; + 17 [shape=box label="Enter block"]; + 18 [shape=box label="Access variable R|/x|"]; + 19 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 20 [shape=box label="Access variable R|/x|"]; + 21 [shape=box label="Function call: R|/x|.R|/B.bar|()"]; + 22 [shape=box label="Access variable R|/x|"]; + 23 [shape=box label="Function call: R|/x|.R|/C.baz|()"]; + 24 [shape=box label="Exit block"]; + 25 [shape=box label="Exit when branch result"]; + 26 [shape=box label="Enter when branch condition else"]; + 27 [shape=box label="Exit when branch condition"]; + 28 [shape=box label="Enter block"]; + 29 [shape=box label="Exit block"]; + 30 [shape=box label="Exit when branch result"]; + 31 [shape=box label="Exit when"]; + 32 [shape=box label="Exit block"]; + 33 [shape=box label="Exit function test_1"]; + + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {15 13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17 26}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {31}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; +} + +subgraph test_2 { + 34 [shape=box label="Enter function test_2"]; + 35 [shape=box label="Enter block"]; + 36 [shape=box label="Enter when"]; + 37 [shape=box label="Enter when branch condition "]; + 38 [shape=box label="Enter ||"]; + 39 [shape=box label="Access variable R|/x|"]; + 40 [shape=box label="Type operator: x is B"]; + 41 [shape=box label="Exit left part of ||"]; + 42 [shape=box label="Access variable R|/x|"]; + 43 [shape=box label="Type operator: x is C"]; + 44 [shape=box label="Exit ||"]; + 45 [shape=box label="Exit when branch condition"]; + 46 [shape=box label="Enter block"]; + 47 [shape=box label="Access variable R|/x|"]; + 48 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 49 [shape=box label="Access variable R|/x|"]; + 50 [shape=box label="Function call: R|/x|.#()"]; + 51 [shape=box label="Access variable R|/x|"]; + 52 [shape=box label="Function call: R|/x|.#()"]; + 53 [shape=box label="Exit block"]; + 54 [shape=box label="Exit when branch result"]; + 55 [shape=box label="Enter when branch condition else"]; + 56 [shape=box label="Exit when branch condition"]; + 57 [shape=box label="Enter block"]; + 58 [shape=box label="Exit block"]; + 59 [shape=box label="Exit when branch result"]; + 60 [shape=box label="Exit when"]; + 61 [shape=box label="Exit block"]; + 62 [shape=box label="Exit function test_2"]; + + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {44 41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {45}; + 45 -> {46 55}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {60}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; +} + +subgraph test_3 { + 63 [shape=box label="Enter function test_3"]; + 64 [shape=box label="Enter block"]; + 65 [shape=box label="Enter when"]; + 66 [shape=box label="Enter when branch condition "]; + 67 [shape=box label="Access variable R|/x|"]; + 68 [shape=box label="Type operator: x !is A"]; + 69 [shape=box label="Function call: (R|/x| !is R|A|).R|kotlin/Boolean.not|()"]; + 70 [shape=box label="Exit when branch condition"]; + 71 [shape=box label="Enter block"]; + 72 [shape=box label="Access variable R|/x|"]; + 73 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 74 [shape=box label="Exit block"]; + 75 [shape=box label="Exit when branch result"]; + 76 [shape=box label="Enter when branch condition else"]; + 77 [shape=box label="Exit when branch condition"]; + 78 [shape=box label="Enter block"]; + 79 [shape=box label="Exit block"]; + 80 [shape=box label="Exit when branch result"]; + 81 [shape=box label="Exit when"]; + 82 [shape=box label="Exit block"]; + 83 [shape=box label="Exit function test_3"]; + + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71 76}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {81}; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; +} + +subgraph test_4 { + 84 [shape=box label="Enter function test_4"]; + 85 [shape=box label="Enter block"]; + 86 [shape=box label="Enter when"]; + 87 [shape=box label="Enter when branch condition "]; + 88 [shape=box label="Enter ||"]; + 89 [shape=box label="Access variable R|/x|"]; + 90 [shape=box label="Type operator: x !is String"]; + 91 [shape=box label="Exit left part of ||"]; + 92 [shape=box label="Access variable R|/x|"]; + 93 [shape=box label="Access variable R|kotlin/String.length|"]; + 94 [shape=box label="Const: Int(0)"]; + 95 [shape=box label="Operator =="]; + 96 [shape=box label="Exit ||"]; + 97 [shape=box label="Exit when branch condition"]; + 98 [shape=box label="Enter block"]; + 99 [shape=box label="Access variable R|/x|"]; + 100 [shape=box label="Access variable #"]; + 101 [shape=box label="Exit block"]; + 102 [shape=box label="Exit when branch result"]; + 103 [shape=box label="Enter when branch condition else"]; + 104 [shape=box label="Exit when branch condition"]; + 105 [shape=box label="Enter block"]; + 106 [shape=box label="Exit block"]; + 107 [shape=box label="Exit when branch result"]; + 108 [shape=box label="Exit when"]; + 109 [shape=box label="Access variable R|/x|"]; + 110 [shape=box label="Access variable #"]; + 111 [shape=box label="Exit block"]; + 112 [shape=box label="Exit function test_4"]; + + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {96 91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {94}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98 103}; + 98 -> {99}; + 99 -> {100}; + 100 -> {101}; + 101 -> {102}; + 102 -> {108}; + 103 -> {104}; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {110}; + 110 -> {111}; + 111 -> {112}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.kt b/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.kt new file mode 100644 index 00000000000..49cf05c9edd --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.kt @@ -0,0 +1,40 @@ +interface A { + fun foo() +} + +interface B : A { + fun bar() +} + +interface C : A { + fun baz() +} + +fun test_1(x: Any) { + if (x is B && x is C) { + x.foo() + x.bar() + x.baz() + } +} + +fun test_2(x: Any) { + if (x is B || x is C) { + x.foo() + x.bar() + x.baz() + } +} + +fun test_3(x: Any) { + if (!(x !is A)) { + x.foo() + } +} + +fun test_4(x: Any) { + if (x !is String || x.length == 0) { + x.length + } + x.length +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.txt b/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.txt new file mode 100644 index 00000000000..74caaa9413b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.txt @@ -0,0 +1,58 @@ +FILE: booleanOperators.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + } + public abstract interface B : R|A| { + public abstract fun bar(): R|kotlin/Unit| + + } + public abstract interface C : R|A| { + public abstract fun baz(): R|kotlin/Unit| + + } + public final fun test_1(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|B|) && (R|/x| is R|C|) -> { + R|/x|.R|/A.foo|() + R|/x|.R|/B.bar|() + R|/x|.R|/C.baz|() + } + else -> { + } + } + + } + public final fun test_2(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|B|) || (R|/x| is R|C|) -> { + R|/x|.R|/A.foo|() + R|/x|.#() + R|/x|.#() + } + else -> { + } + } + + } + public final fun test_3(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| !is R|A|).R|kotlin/Boolean.not|() -> { + R|/x|.R|/A.foo|() + } + else -> { + } + } + + } + public final fun test_4(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| !is R|kotlin/String|) || ==(R|/x|.R|kotlin/String.length|, Int(0)) -> { + R|/x|.# + } + else -> { + } + } + + R|/x|.# + } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/casts.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/casts.cfg.dot new file mode 100644 index 00000000000..e6eebd5e0a4 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/casts.cfg.dot @@ -0,0 +1,310 @@ +digraph casts_kt { +subgraph test_1 { + 0 [shape=box label="Enter function test_1"]; + 1 [shape=box label="Enter block"]; + 2 [shape=box label="Access variable R|/x|"]; + 3 [shape=box label="Type operator: x as String"]; + 4 [shape=box label="Access variable R|/x|"]; + 5 [shape=box label="Access variable R|kotlin/String.length|"]; + 6 [shape=box label="Exit block"]; + 7 [shape=box label="Exit function test_1"]; + + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; +} + +subgraph test_2 { + 8 [shape=box label="Enter function test_2"]; + 9 [shape=box label="Enter block"]; + 10 [shape=box label="Enter when"]; + 11 [shape=box label="Enter when branch condition "]; + 12 [shape=box label="Access variable R|/x|"]; + 13 [shape=box label="Type operator: x as Boolean"]; + 14 [shape=box label="Exit when branch condition"]; + 15 [shape=box label="Enter block"]; + 16 [shape=box label="Access variable R|/x|"]; + 17 [shape=box label="Function call: R|/x|.R|kotlin/Boolean.not|()"]; + 18 [shape=box label="Exit block"]; + 19 [shape=box label="Exit when branch result"]; + 20 [shape=box label="Enter when branch condition else"]; + 21 [shape=box label="Exit when branch condition"]; + 22 [shape=box label="Enter block"]; + 23 [shape=box label="Exit block"]; + 24 [shape=box label="Exit when branch result"]; + 25 [shape=box label="Exit when"]; + 26 [shape=box label="Access variable R|/x|"]; + 27 [shape=box label="Function call: R|/x|.R|kotlin/Boolean.not|()"]; + 28 [shape=box label="Exit block"]; + 29 [shape=box label="Exit function test_2"]; + + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15 20}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {25}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; +} + +subgraph test_3 { + 30 [shape=box label="Enter function test_3"]; + 31 [shape=box label="Enter block"]; + 32 [shape=box label="Enter when"]; + 33 [shape=box label="Enter when branch condition "]; + 34 [shape=box label="Enter &&"]; + 35 [shape=box label="Access variable R|/b|"]; + 36 [shape=box label="Access variable R|/x|"]; + 37 [shape=box label="Type operator: x as Boolean"]; + 38 [shape=box label="Exit &&"]; + 39 [shape=box label="Exit when branch condition"]; + 40 [shape=box label="Enter block"]; + 41 [shape=box label="Access variable R|/x|"]; + 42 [shape=box label="Function call: R|/x|.R|kotlin/Boolean.not|()"]; + 43 [shape=box label="Exit block"]; + 44 [shape=box label="Exit when branch result"]; + 45 [shape=box label="Enter when branch condition else"]; + 46 [shape=box label="Exit when branch condition"]; + 47 [shape=box label="Enter block"]; + 48 [shape=box label="Exit block"]; + 49 [shape=box label="Exit when branch result"]; + 50 [shape=box label="Exit when"]; + 51 [shape=box label="Access variable R|/x|"]; + 52 [shape=box label="Function call: R|/x|.#()"]; + 53 [shape=box label="Enter when"]; + 54 [shape=box label="Enter when branch condition "]; + 55 [shape=box label="Enter &&"]; + 56 [shape=box label="Access variable R|/b|"]; + 57 [shape=box label="Access variable R|/x|"]; + 58 [shape=box label="Type operator: x as Boolean"]; + 59 [shape=box label="Const: Boolean(true)"]; + 60 [shape=box label="Operator =="]; + 61 [shape=box label="Exit &&"]; + 62 [shape=box label="Exit when branch condition"]; + 63 [shape=box label="Enter block"]; + 64 [shape=box label="Access variable R|/x|"]; + 65 [shape=box label="Function call: R|/x|.R|kotlin/Boolean.not|()"]; + 66 [shape=box label="Exit block"]; + 67 [shape=box label="Exit when branch result"]; + 68 [shape=box label="Enter when branch condition else"]; + 69 [shape=box label="Exit when branch condition"]; + 70 [shape=box label="Enter block"]; + 71 [shape=box label="Exit block"]; + 72 [shape=box label="Exit when branch result"]; + 73 [shape=box label="Exit when"]; + 74 [shape=box label="Access variable R|/x|"]; + 75 [shape=box label="Function call: R|/x|.#()"]; + 76 [shape=box label="Enter when"]; + 77 [shape=box label="Enter when branch condition "]; + 78 [shape=box label="Enter ||"]; + 79 [shape=box label="Access variable R|/b|"]; + 80 [shape=box label="Exit left part of ||"]; + 81 [shape=box label="Access variable R|/x|"]; + 82 [shape=box label="Type operator: x as Boolean"]; + 83 [shape=box label="Exit ||"]; + 84 [shape=box label="Exit when branch condition"]; + 85 [shape=box label="Enter block"]; + 86 [shape=box label="Access variable R|/x|"]; + 87 [shape=box label="Function call: R|/x|.#()"]; + 88 [shape=box label="Exit block"]; + 89 [shape=box label="Exit when branch result"]; + 90 [shape=box label="Enter when branch condition else"]; + 91 [shape=box label="Exit when branch condition"]; + 92 [shape=box label="Enter block"]; + 93 [shape=box label="Exit block"]; + 94 [shape=box label="Exit when branch result"]; + 95 [shape=box label="Exit when"]; + 96 [shape=box label="Access variable R|/x|"]; + 97 [shape=box label="Function call: R|/x|.#()"]; + 98 [shape=box label="Exit block"]; + 99 [shape=box label="Exit function test_3"]; + + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {38 36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40 45}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {50}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {61 57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63 68}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {73}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + 79 -> {83 80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85 90}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {95}; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {94}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; +} + +subgraph test_4 { + 100 [shape=box label="Enter function test_4"]; + 101 [shape=box label="Enter block"]; + 102 [shape=box label="Enter when"]; + 103 [shape=box label="Enter when branch condition "]; + 104 [shape=box label="Access variable R|/b|"]; + 105 [shape=box label="Type operator: b as? Boolean"]; + 106 [shape=box label="Const: Null(null)"]; + 107 [shape=box label="Operator !="]; + 108 [shape=box label="Exit when branch condition"]; + 109 [shape=box label="Enter block"]; + 110 [shape=box label="Access variable R|/b|"]; + 111 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 112 [shape=box label="Exit block"]; + 113 [shape=box label="Exit when branch result"]; + 114 [shape=box label="Enter when branch condition else"]; + 115 [shape=box label="Exit when branch condition"]; + 116 [shape=box label="Enter block"]; + 117 [shape=box label="Access variable R|/b|"]; + 118 [shape=box label="Function call: R|/b|.#()"]; + 119 [shape=box label="Exit block"]; + 120 [shape=box label="Exit when branch result"]; + 121 [shape=box label="Exit when"]; + 122 [shape=box label="Access variable R|/b|"]; + 123 [shape=box label="Function call: R|/b|.#()"]; + 124 [shape=box label="Enter when"]; + 125 [shape=box label="Enter when branch condition "]; + 126 [shape=box label="Access variable R|/b|"]; + 127 [shape=box label="Type operator: b as? Boolean"]; + 128 [shape=box label="Const: Null(null)"]; + 129 [shape=box label="Operator =="]; + 130 [shape=box label="Exit when branch condition"]; + 131 [shape=box label="Enter block"]; + 132 [shape=box label="Access variable R|/b|"]; + 133 [shape=box label="Function call: R|/b|.#()"]; + 134 [shape=box label="Exit block"]; + 135 [shape=box label="Exit when branch result"]; + 136 [shape=box label="Enter when branch condition else"]; + 137 [shape=box label="Exit when branch condition"]; + 138 [shape=box label="Enter block"]; + 139 [shape=box label="Access variable R|/b|"]; + 140 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 141 [shape=box label="Exit block"]; + 142 [shape=box label="Exit when branch result"]; + 143 [shape=box label="Exit when"]; + 144 [shape=box label="Access variable R|/b|"]; + 145 [shape=box label="Function call: R|/b|.#()"]; + 146 [shape=box label="Exit block"]; + 147 [shape=box label="Exit function test_4"]; + + 100 -> {101}; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109 114}; + 109 -> {110}; + 110 -> {111}; + 111 -> {112}; + 112 -> {113}; + 113 -> {121}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; + 128 -> {129}; + 129 -> {130}; + 130 -> {131 136}; + 131 -> {132}; + 132 -> {133}; + 133 -> {134}; + 134 -> {135}; + 135 -> {143}; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; + 139 -> {140}; + 140 -> {141}; + 141 -> {142}; + 142 -> {143}; + 143 -> {144}; + 144 -> {145}; + 145 -> {146}; + 146 -> {147}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/casts.kt b/compiler/fir/resolve/testData/resolve/smartcasts/casts.kt new file mode 100644 index 00000000000..ae5cbbf2d30 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/casts.kt @@ -0,0 +1,44 @@ +fun test_1(x: Any?) { + x as String + x.length +} + +fun test_2(x: Any?) { + if (x as Boolean) { + x.not() + } + x.not() +} + +fun test_3(b: Boolean, x: Any?) { + if (b && x as Boolean) { + x.not() + } + x.not() + + if (b && x as Boolean == true) { + x.not() + } + x.not() + + if (b || x as Boolean) { + x.not() + } + x.not() +} + +fun test_4(b: Any) { + if (b as? Boolean != null) { + b.not() + } else { + b.not() + } + b.not() + + if (b as? Boolean == null) { + b.not() + } else { + b.not() + } + b.not() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/casts.txt b/compiler/fir/resolve/testData/resolve/smartcasts/casts.txt new file mode 100644 index 00000000000..a4e1b38f408 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/casts.txt @@ -0,0 +1,67 @@ +FILE: casts.kt + public final fun test_1(x: R|kotlin/Any?|): R|kotlin/Unit| { + (R|/x| as R|kotlin/String|) + R|/x|.R|kotlin/String.length| + } + public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| { + when () { + (R|/x| as R|kotlin/Boolean|) -> { + R|/x|.R|kotlin/Boolean.not|() + } + else -> { + } + } + + R|/x|.R|kotlin/Boolean.not|() + } + public final fun test_3(b: R|kotlin/Boolean|, x: R|kotlin/Any?|): R|kotlin/Unit| { + when () { + R|/b| && (R|/x| as R|kotlin/Boolean|) -> { + R|/x|.R|kotlin/Boolean.not|() + } + else -> { + } + } + + R|/x|.#() + when () { + R|/b| && ==((R|/x| as R|kotlin/Boolean|), Boolean(true)) -> { + R|/x|.R|kotlin/Boolean.not|() + } + else -> { + } + } + + R|/x|.#() + when () { + R|/b| || (R|/x| as R|kotlin/Boolean|) -> { + R|/x|.#() + } + else -> { + } + } + + R|/x|.#() + } + public final fun test_4(b: R|kotlin/Any|): R|kotlin/Unit| { + when () { + !=((R|/b| as? R|kotlin/Boolean|), Null(null)) -> { + R|/b|.R|kotlin/Boolean.not|() + } + else -> { + R|/b|.#() + } + } + + R|/b|.#() + when () { + ==((R|/b| as? R|kotlin/Boolean|), Null(null)) -> { + R|/b|.#() + } + else -> { + R|/b|.R|kotlin/Boolean.not|() + } + } + + R|/b|.#() + } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.cfg.dot new file mode 100644 index 00000000000..8e0be6a0f66 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.cfg.dot @@ -0,0 +1,305 @@ +digraph equalsAndIdentity_kt { +subgraph foo { + 0 [shape=box label="Enter function foo"]; + 1 [shape=box label="Exit function foo"]; + + 0 -> {1}; +} + +subgraph test_1 { + 2 [shape=box label="Enter function test_1"]; + 3 [shape=box label="Enter block"]; + 4 [shape=box label="Enter when"]; + 5 [shape=box label="Enter when branch condition "]; + 6 [shape=box label="Access variable R|/x|"]; + 7 [shape=box label="Access variable R|/y|"]; + 8 [shape=box label="Operator =="]; + 9 [shape=box label="Exit when branch condition"]; + 10 [shape=box label="Enter block"]; + 11 [shape=box label="Access variable R|/x|"]; + 12 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 13 [shape=box label="Access variable R|/y|"]; + 14 [shape=box label="Function call: R|/y|.R|/A.foo|()"]; + 15 [shape=box label="Exit block"]; + 16 [shape=box label="Exit when branch result"]; + 17 [shape=box label="Enter when branch condition else"]; + 18 [shape=box label="Exit when branch condition"]; + 19 [shape=box label="Enter block"]; + 20 [shape=box label="Exit block"]; + 21 [shape=box label="Exit when branch result"]; + 22 [shape=box label="Exit when"]; + 23 [shape=box label="Enter when"]; + 24 [shape=box label="Enter when branch condition "]; + 25 [shape=box label="Access variable R|/x|"]; + 26 [shape=box label="Access variable R|/y|"]; + 27 [shape=box label="Operator ==="]; + 28 [shape=box label="Exit when branch condition"]; + 29 [shape=box label="Enter block"]; + 30 [shape=box label="Access variable R|/x|"]; + 31 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 32 [shape=box label="Access variable R|/y|"]; + 33 [shape=box label="Function call: R|/y|.R|/A.foo|()"]; + 34 [shape=box label="Exit block"]; + 35 [shape=box label="Exit when branch result"]; + 36 [shape=box label="Enter when branch condition else"]; + 37 [shape=box label="Exit when branch condition"]; + 38 [shape=box label="Enter block"]; + 39 [shape=box label="Exit block"]; + 40 [shape=box label="Exit when branch result"]; + 41 [shape=box label="Exit when"]; + 42 [shape=box label="Exit block"]; + 43 [shape=box label="Exit function test_1"]; + + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10 17}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {22}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29 36}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {41}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; +} + +subgraph test_2 { + 44 [shape=box label="Enter function test_2"]; + 45 [shape=box label="Enter block"]; + 46 [shape=box label="Enter when"]; + 47 [shape=box label="Enter when branch condition "]; + 48 [shape=box label="Access variable R|/x|"]; + 49 [shape=box label="Access variable R|/y|"]; + 50 [shape=box label="Operator =="]; + 51 [shape=box label="Exit when branch condition"]; + 52 [shape=box label="Enter block"]; + 53 [shape=box label="Access variable R|/x|"]; + 54 [shape=box label="Function call: R|/x|.#()"]; + 55 [shape=box label="Access variable R|/y|"]; + 56 [shape=box label="Function call: R|/y|.#()"]; + 57 [shape=box label="Exit block"]; + 58 [shape=box label="Exit when branch result"]; + 59 [shape=box label="Enter when branch condition else"]; + 60 [shape=box label="Exit when branch condition"]; + 61 [shape=box label="Enter block"]; + 62 [shape=box label="Exit block"]; + 63 [shape=box label="Exit when branch result"]; + 64 [shape=box label="Exit when"]; + 65 [shape=box label="Enter when"]; + 66 [shape=box label="Enter when branch condition "]; + 67 [shape=box label="Access variable R|/x|"]; + 68 [shape=box label="Access variable R|/y|"]; + 69 [shape=box label="Operator ==="]; + 70 [shape=box label="Exit when branch condition"]; + 71 [shape=box label="Enter block"]; + 72 [shape=box label="Access variable R|/x|"]; + 73 [shape=box label="Function call: R|/x|.#()"]; + 74 [shape=box label="Access variable R|/y|"]; + 75 [shape=box label="Function call: R|/y|.#()"]; + 76 [shape=box label="Exit block"]; + 77 [shape=box label="Exit when branch result"]; + 78 [shape=box label="Enter when branch condition else"]; + 79 [shape=box label="Exit when branch condition"]; + 80 [shape=box label="Enter block"]; + 81 [shape=box label="Exit block"]; + 82 [shape=box label="Exit when branch result"]; + 83 [shape=box label="Exit when"]; + 84 [shape=box label="Exit block"]; + 85 [shape=box label="Exit function test_2"]; + + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52 59}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {64}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71 78}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {77}; + 77 -> {83}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; +} + +subgraph test_3 { + 86 [shape=box label="Enter function test_3"]; + 87 [shape=box label="Enter block"]; + 88 [shape=box label="Enter when"]; + 89 [shape=box label="Enter when branch condition "]; + 90 [shape=box label="Access variable R|/y|"]; + 91 [shape=box label="Const: Null(null)"]; + 92 [shape=box label="Operator =="]; + 93 [shape=box label="Exit when branch condition"]; + 94 [shape=box label="Enter block"]; + 95 [shape=box label="Jump: ^test_3 Unit"]; + 96 [shape=box label="Stub[DEAD]"]; + 97 [shape=box label="Exit block[DEAD]"]; + 98 [shape=box label="Exit when branch result[DEAD]"]; + 99 [shape=box label="Enter when branch condition else"]; + 100 [shape=box label="Exit when branch condition"]; + 101 [shape=box label="Enter block"]; + 102 [shape=box label="Exit block"]; + 103 [shape=box label="Exit when branch result"]; + 104 [shape=box label="Exit when"]; + 105 [shape=box label="Enter when"]; + 106 [shape=box label="Enter when branch condition "]; + 107 [shape=box label="Access variable R|/x|"]; + 108 [shape=box label="Access variable R|/y|"]; + 109 [shape=box label="Operator =="]; + 110 [shape=box label="Exit when branch condition"]; + 111 [shape=box label="Enter block"]; + 112 [shape=box label="Access variable R|/x|"]; + 113 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 114 [shape=box label="Access variable R|/y|"]; + 115 [shape=box label="Function call: R|/y|.R|/A.foo|()"]; + 116 [shape=box label="Exit block"]; + 117 [shape=box label="Exit when branch result"]; + 118 [shape=box label="Enter when branch condition else"]; + 119 [shape=box label="Exit when branch condition"]; + 120 [shape=box label="Enter block"]; + 121 [shape=box label="Exit block"]; + 122 [shape=box label="Exit when branch result"]; + 123 [shape=box label="Exit when"]; + 124 [shape=box label="Enter when"]; + 125 [shape=box label="Enter when branch condition "]; + 126 [shape=box label="Access variable R|/x|"]; + 127 [shape=box label="Access variable R|/y|"]; + 128 [shape=box label="Operator ==="]; + 129 [shape=box label="Exit when branch condition"]; + 130 [shape=box label="Enter block"]; + 131 [shape=box label="Access variable R|/x|"]; + 132 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 133 [shape=box label="Access variable R|/y|"]; + 134 [shape=box label="Function call: R|/y|.R|/A.foo|()"]; + 135 [shape=box label="Exit block"]; + 136 [shape=box label="Exit when branch result"]; + 137 [shape=box label="Enter when branch condition else"]; + 138 [shape=box label="Exit when branch condition"]; + 139 [shape=box label="Enter block"]; + 140 [shape=box label="Exit block"]; + 141 [shape=box label="Exit when branch result"]; + 142 [shape=box label="Exit when"]; + 143 [shape=box label="Exit block"]; + 144 [shape=box label="Exit function test_3"]; + + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {94 99}; + 94 -> {95}; + 95 -> {144}; + 95 -> {96} [style=dotted]; + 96 -> {97} [style=dotted]; + 97 -> {98} [style=dotted]; + 98 -> {104} [style=dotted]; + 99 -> {100}; + 100 -> {101}; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {110}; + 110 -> {111 118}; + 111 -> {112}; + 112 -> {113}; + 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {123}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; + 128 -> {129}; + 129 -> {130 137}; + 130 -> {131}; + 131 -> {132}; + 132 -> {133}; + 133 -> {134}; + 134 -> {135}; + 135 -> {136}; + 136 -> {142}; + 137 -> {138}; + 138 -> {139}; + 139 -> {140}; + 140 -> {141}; + 141 -> {142}; + 142 -> {143}; + 143 -> {144}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt b/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt new file mode 100644 index 00000000000..a53fe324127 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt @@ -0,0 +1,37 @@ +interface A { + fun foo() +} + +fun test_1(x: A, y: A?) { + if (x == y) { + x.foo() + y.foo() + } + if (x === y) { + x.foo() + y.foo() + } +} + +fun test_2(x: A?, y: A?) { + if (x == y) { + x.foo() + y.foo() + } + if (x === y) { + x.foo() + y.foo() + } +} + +fun test_3(x: A?, y: A?) { + if (y == null) return + if (x == y) { + x.foo() + y.foo() + } + if (x === y) { + x.foo() + y.foo() + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.txt b/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.txt new file mode 100644 index 00000000000..5caef1b14c5 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.txt @@ -0,0 +1,73 @@ +FILE: equalsAndIdentity.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + } + public final fun test_1(x: R|A|, y: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/x|, R|/y|) -> { + R|/x|.R|/A.foo|() + R|/y|.R|/A.foo|() + } + else -> { + } + } + + when () { + ===(R|/x|, R|/y|) -> { + R|/x|.R|/A.foo|() + R|/y|.R|/A.foo|() + } + else -> { + } + } + + } + public final fun test_2(x: R|A?|, y: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/x|, R|/y|) -> { + R|/x|.#() + R|/y|.#() + } + else -> { + } + } + + when () { + ===(R|/x|, R|/y|) -> { + R|/x|.#() + R|/y|.#() + } + else -> { + } + } + + } + public final fun test_3(x: R|A?|, y: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/y|, Null(null)) -> { + ^test_3 Unit + } + else -> { + } + } + + when () { + ==(R|/x|, R|/y|) -> { + R|/x|.R|/A.foo|() + R|/y|.R|/A.foo|() + } + else -> { + } + } + + when () { + ===(R|/x|, R|/y|) -> { + R|/x|.R|/A.foo|() + R|/y|.R|/A.foo|() + } + else -> { + } + } + + } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.cfg.dot new file mode 100644 index 00000000000..93fb2c41321 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.cfg.dot @@ -0,0 +1,831 @@ +digraph nullability_kt { +subgraph foo { + 0 [shape=box label="Enter function foo"]; + 1 [shape=box label="Exit function foo"]; + + 0 -> {1}; +} + +subgraph getA { + 2 [shape=box label="Enter function getA"]; + 3 [shape=box label="Exit function getA"]; + + 2 -> {3}; +} + +subgraph val_s { + 4 [shape=box label="Enter property"]; + 5 [shape=box label="Exit property"]; + + 4 -> {5}; +} + +subgraph fs { + 6 [shape=box label="Enter function fs"]; + 7 [shape=box label="Exit function fs"]; + + 6 -> {7}; +} + +subgraph val_data { + 8 [shape=box label="Enter property"]; + 9 [shape=box label="Exit property"]; + + 8 -> {9}; +} + +subgraph fdata { + 10 [shape=box label="Enter function fdata"]; + 11 [shape=box label="Exit function fdata"]; + + 10 -> {11}; +} + +subgraph test_1 { + 12 [shape=box label="Enter function test_1"]; + 13 [shape=box label="Enter block"]; + 14 [shape=box label="Enter when"]; + 15 [shape=box label="Enter when branch condition "]; + 16 [shape=box label="Access variable R|/x|"]; + 17 [shape=box label="Const: Null(null)"]; + 18 [shape=box label="Operator !="]; + 19 [shape=box label="Exit when branch condition"]; + 20 [shape=box label="Enter block"]; + 21 [shape=box label="Access variable R|/x|"]; + 22 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 23 [shape=box label="Exit block"]; + 24 [shape=box label="Exit when branch result"]; + 25 [shape=box label="Enter when branch condition else"]; + 26 [shape=box label="Exit when branch condition"]; + 27 [shape=box label="Enter block"]; + 28 [shape=box label="Access variable R|/x|"]; + 29 [shape=box label="Function call: R|/x|.#()"]; + 30 [shape=box label="Exit block"]; + 31 [shape=box label="Exit when branch result"]; + 32 [shape=box label="Exit when"]; + 33 [shape=box label="Access variable R|/x|"]; + 34 [shape=box label="Function call: R|/x|.#()"]; + 35 [shape=box label="Exit block"]; + 36 [shape=box label="Exit function test_1"]; + + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20 25}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {32}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {36}; +} + +subgraph test_2 { + 37 [shape=box label="Enter function test_2"]; + 38 [shape=box label="Enter block"]; + 39 [shape=box label="Enter when"]; + 40 [shape=box label="Enter when branch condition "]; + 41 [shape=box label="Access variable R|/x|"]; + 42 [shape=box label="Const: Null(null)"]; + 43 [shape=box label="Operator =="]; + 44 [shape=box label="Exit when branch condition"]; + 45 [shape=box label="Enter block"]; + 46 [shape=box label="Access variable R|/x|"]; + 47 [shape=box label="Function call: R|/x|.#()"]; + 48 [shape=box label="Exit block"]; + 49 [shape=box label="Exit when branch result"]; + 50 [shape=box label="Enter when branch condition else"]; + 51 [shape=box label="Exit when branch condition"]; + 52 [shape=box label="Enter block"]; + 53 [shape=box label="Access variable R|/x|"]; + 54 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 55 [shape=box label="Exit block"]; + 56 [shape=box label="Exit when branch result"]; + 57 [shape=box label="Exit when"]; + 58 [shape=box label="Access variable R|/x|"]; + 59 [shape=box label="Function call: R|/x|.#()"]; + 60 [shape=box label="Exit block"]; + 61 [shape=box label="Exit function test_2"]; + + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {45 50}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {57}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; +} + +subgraph test_3 { + 62 [shape=box label="Enter function test_3"]; + 63 [shape=box label="Enter block"]; + 64 [shape=box label="Enter when"]; + 65 [shape=box label="Access variable R|/x|"]; + 66 [shape=box label="Variable declaration: lval : R|A?|"]; + 67 [shape=box label="Enter when branch condition "]; + 68 [shape=box label="Const: Null(null)"]; + 69 [shape=box label="Operator =="]; + 70 [shape=box label="Exit when branch condition"]; + 71 [shape=box label="Enter block"]; + 72 [shape=box label="Jump: ^test_3 Unit"]; + 73 [shape=box label="Stub[DEAD]"]; + 74 [shape=box label="Exit block[DEAD]"]; + 75 [shape=box label="Exit when branch result[DEAD]"]; + 76 [shape=box label="Enter when branch condition else"]; + 77 [shape=box label="Exit when branch condition"]; + 78 [shape=box label="Enter block"]; + 79 [shape=box label="Access variable R|/|"]; + 80 [shape=box label="Exit block"]; + 81 [shape=box label="Exit when branch result"]; + 82 [shape=box label="Exit when"]; + 83 [shape=box label="Access variable R|/x|"]; + 84 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 85 [shape=box label="Exit block"]; + 86 [shape=box label="Exit function test_3"]; + + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71 76}; + 71 -> {72}; + 72 -> {86}; + 72 -> {73} [style=dotted]; + 73 -> {74} [style=dotted]; + 74 -> {75} [style=dotted]; + 75 -> {82} [style=dotted]; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {86}; +} + +subgraph test_4 { + 87 [shape=box label="Enter function test_4"]; + 88 [shape=box label="Enter block"]; + 89 [shape=box label="Enter when"]; + 90 [shape=box label="Enter when branch condition "]; + 91 [shape=box label="Access variable R|/x|"]; + 92 [shape=box label="Function call: R|/x|?.R|/A.getA|()"]; + 93 [shape=box label="Const: Null(null)"]; + 94 [shape=box label="Operator =="]; + 95 [shape=box label="Exit when branch condition"]; + 96 [shape=box label="Enter block"]; + 97 [shape=box label="Jump: ^test_4 Unit"]; + 98 [shape=box label="Stub[DEAD]"]; + 99 [shape=box label="Exit block[DEAD]"]; + 100 [shape=box label="Exit when branch result[DEAD]"]; + 101 [shape=box label="Enter when branch condition else"]; + 102 [shape=box label="Exit when branch condition"]; + 103 [shape=box label="Enter block"]; + 104 [shape=box label="Exit block"]; + 105 [shape=box label="Exit when branch result"]; + 106 [shape=box label="Exit when"]; + 107 [shape=box label="Access variable R|/x|"]; + 108 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 109 [shape=box label="Exit block"]; + 110 [shape=box label="Exit function test_4"]; + + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {94}; + 94 -> {95}; + 95 -> {96 101}; + 96 -> {97}; + 97 -> {110}; + 97 -> {98} [style=dotted]; + 98 -> {99} [style=dotted]; + 99 -> {100} [style=dotted]; + 100 -> {106} [style=dotted]; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {110}; +} + +subgraph test_5 { + 111 [shape=box label="Enter function test_5"]; + 112 [shape=box label="Enter block"]; + 113 [shape=box label="Enter when"]; + 114 [shape=box label="Enter when branch condition "]; + 115 [shape=box label="Access variable R|/q|"]; + 116 [shape=box label="Access variable R|/Q.data|"]; + 117 [shape=box label="Access variable R|/MyData.s|"]; + 118 [shape=box label="Function call: R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()"]; + 119 [shape=box label="Const: Null(null)"]; + 120 [shape=box label="Operator !="]; + 121 [shape=box label="Exit when branch condition"]; + 122 [shape=box label="Enter block"]; + 123 [shape=box label="Access variable R|/q|"]; + 124 [shape=box label="Access variable R|/Q.data|"]; + 125 [shape=box label="Access variable R|/q|"]; + 126 [shape=box label="Access variable R|/Q.data|"]; + 127 [shape=box label="Access variable R|/MyData.s|"]; + 128 [shape=box label="Access variable R|/q|"]; + 129 [shape=box label="Access variable R|/Q.data|"]; + 130 [shape=box label="Access variable R|/MyData.s|"]; + 131 [shape=box label="Function call: R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; + 132 [shape=box label="Exit block"]; + 133 [shape=box label="Exit when branch result"]; + 134 [shape=box label="Enter when branch condition else"]; + 135 [shape=box label="Exit when branch condition"]; + 136 [shape=box label="Enter block"]; + 137 [shape=box label="Exit block"]; + 138 [shape=box label="Exit when branch result"]; + 139 [shape=box label="Exit when"]; + 140 [shape=box label="Exit block"]; + 141 [shape=box label="Exit function test_5"]; + + 111 -> {112}; + 112 -> {113}; + 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122 134}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; + 128 -> {129}; + 129 -> {130}; + 130 -> {131}; + 131 -> {132}; + 132 -> {133}; + 133 -> {139}; + 134 -> {135}; + 135 -> {136}; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; + 139 -> {140}; + 140 -> {141}; +} + +subgraph test_6 { + 142 [shape=box label="Enter function test_6"]; + 143 [shape=box label="Enter block"]; + 144 [shape=box label="Enter when"]; + 145 [shape=box label="Access variable R|/q|"]; + 146 [shape=box label="Access variable R|/Q.data|"]; + 147 [shape=box label="Access variable R|/MyData.s|"]; + 148 [shape=box label="Function call: R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()"]; + 149 [shape=box label="Variable declaration: lval : R|kotlin/Int|"]; + 150 [shape=box label="Enter when branch condition "]; + 151 [shape=box label="Const: Null(null)"]; + 152 [shape=box label="Operator =="]; + 153 [shape=box label="Exit when branch condition"]; + 154 [shape=box label="Enter block"]; + 155 [shape=box label="Jump: ^test_6 Unit"]; + 156 [shape=box label="Stub[DEAD]"]; + 157 [shape=box label="Exit block[DEAD]"]; + 158 [shape=box label="Exit when branch result[DEAD]"]; + 159 [shape=box label="Enter when branch condition else"]; + 160 [shape=box label="Exit when branch condition"]; + 161 [shape=box label="Enter block"]; + 162 [shape=box label="Access variable R|/|"]; + 163 [shape=box label="Exit block"]; + 164 [shape=box label="Exit when branch result"]; + 165 [shape=box label="Exit when"]; + 166 [shape=box label="Access variable R|/q|"]; + 167 [shape=box label="Access variable R|/Q.data|"]; + 168 [shape=box label="Access variable R|/q|"]; + 169 [shape=box label="Access variable R|/Q.data|"]; + 170 [shape=box label="Access variable R|/MyData.s|"]; + 171 [shape=box label="Access variable R|/q|"]; + 172 [shape=box label="Access variable R|/Q.data|"]; + 173 [shape=box label="Access variable R|/MyData.s|"]; + 174 [shape=box label="Function call: R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; + 175 [shape=box label="Exit block"]; + 176 [shape=box label="Exit function test_6"]; + + 142 -> {143}; + 143 -> {144}; + 144 -> {145}; + 145 -> {146}; + 146 -> {147}; + 147 -> {148}; + 148 -> {149}; + 149 -> {150}; + 150 -> {151}; + 151 -> {152}; + 152 -> {153}; + 153 -> {154 159}; + 154 -> {155}; + 155 -> {176}; + 155 -> {156} [style=dotted]; + 156 -> {157} [style=dotted]; + 157 -> {158} [style=dotted]; + 158 -> {165} [style=dotted]; + 159 -> {160}; + 160 -> {161}; + 161 -> {162}; + 162 -> {163}; + 163 -> {164}; + 164 -> {165}; + 165 -> {166}; + 166 -> {167}; + 167 -> {168}; + 168 -> {169}; + 169 -> {170}; + 170 -> {171}; + 171 -> {172}; + 172 -> {173}; + 173 -> {174}; + 174 -> {175}; + 175 -> {176}; +} + +subgraph test_7 { + 177 [shape=box label="Enter function test_7"]; + 178 [shape=box label="Enter block"]; + 179 [shape=box label="Enter when"]; + 180 [shape=box label="Enter when branch condition "]; + 181 [shape=box label="Access variable R|/q|"]; + 182 [shape=box label="Function call: R|/q|?.R|/Q.fdata|()"]; + 183 [shape=box label="Function call: R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()"]; + 184 [shape=box label="Function call: R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()?.R|kotlin/Int.inc|()"]; + 185 [shape=box label="Const: Null(null)"]; + 186 [shape=box label="Operator !="]; + 187 [shape=box label="Exit when branch condition"]; + 188 [shape=box label="Enter block"]; + 189 [shape=box label="Access variable R|/q|"]; + 190 [shape=box label="Function call: R|/q|.R|/Q.fdata|()"]; + 191 [shape=box label="Access variable R|/q|"]; + 192 [shape=box label="Function call: R|/q|.R|/Q.fdata|()"]; + 193 [shape=box label="Function call: R|/q|.R|/Q.fdata|().#()"]; + 194 [shape=box label="Access variable R|/q|"]; + 195 [shape=box label="Function call: R|/q|.R|/Q.fdata|()"]; + 196 [shape=box label="Function call: R|/q|.R|/Q.fdata|().#()"]; + 197 [shape=box label="Function call: R|/q|.R|/Q.fdata|().#().#()"]; + 198 [shape=box label="Exit block"]; + 199 [shape=box label="Exit when branch result"]; + 200 [shape=box label="Enter when branch condition else"]; + 201 [shape=box label="Exit when branch condition"]; + 202 [shape=box label="Enter block"]; + 203 [shape=box label="Exit block"]; + 204 [shape=box label="Exit when branch result"]; + 205 [shape=box label="Exit when"]; + 206 [shape=box label="Exit block"]; + 207 [shape=box label="Exit function test_7"]; + + 177 -> {178}; + 178 -> {179}; + 179 -> {180}; + 180 -> {181}; + 181 -> {182}; + 182 -> {183}; + 183 -> {184}; + 184 -> {185}; + 185 -> {186}; + 186 -> {187}; + 187 -> {188 200}; + 188 -> {189}; + 189 -> {190}; + 190 -> {191}; + 191 -> {192}; + 192 -> {193}; + 193 -> {194}; + 194 -> {195}; + 195 -> {196}; + 196 -> {197}; + 197 -> {198}; + 198 -> {199}; + 199 -> {205}; + 200 -> {201}; + 201 -> {202}; + 202 -> {203}; + 203 -> {204}; + 204 -> {205}; + 205 -> {206}; + 206 -> {207}; +} + +subgraph test_8 { + 208 [shape=box label="Enter function test_8"]; + 209 [shape=box label="Enter block"]; + 210 [shape=box label="Enter when"]; + 211 [shape=box label="Enter when branch condition "]; + 212 [shape=box label="Access variable R|/b|"]; + 213 [shape=box label="Const: Boolean(true)"]; + 214 [shape=box label="Operator =="]; + 215 [shape=box label="Exit when branch condition"]; + 216 [shape=box label="Enter block"]; + 217 [shape=box label="Access variable R|/b|"]; + 218 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 219 [shape=box label="Exit block"]; + 220 [shape=box label="Exit when branch result"]; + 221 [shape=box label="Enter when branch condition else"]; + 222 [shape=box label="Exit when branch condition"]; + 223 [shape=box label="Enter block"]; + 224 [shape=box label="Exit block"]; + 225 [shape=box label="Exit when branch result"]; + 226 [shape=box label="Exit when"]; + 227 [shape=box label="Exit block"]; + 228 [shape=box label="Exit function test_8"]; + + 208 -> {209}; + 209 -> {210}; + 210 -> {211}; + 211 -> {212}; + 212 -> {213}; + 213 -> {214}; + 214 -> {215}; + 215 -> {216 221}; + 216 -> {217}; + 217 -> {218}; + 218 -> {219}; + 219 -> {220}; + 220 -> {226}; + 221 -> {222}; + 222 -> {223}; + 223 -> {224}; + 224 -> {225}; + 225 -> {226}; + 226 -> {227}; + 227 -> {228}; +} + +subgraph test_9 { + 229 [shape=box label="Enter function test_9"]; + 230 [shape=box label="Enter block"]; + 231 [shape=box label="Enter when"]; + 232 [shape=box label="Enter when branch condition "]; + 233 [shape=box label="Access variable R|/a|"]; + 234 [shape=box label="Access variable R|/b|"]; + 235 [shape=box label="Operator =="]; + 236 [shape=box label="Exit when branch condition"]; + 237 [shape=box label="Enter block"]; + 238 [shape=box label="Access variable R|/b|"]; + 239 [shape=box label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 240 [shape=box label="Exit block"]; + 241 [shape=box label="Exit when branch result"]; + 242 [shape=box label="Enter when branch condition else"]; + 243 [shape=box label="Exit when branch condition"]; + 244 [shape=box label="Enter block"]; + 245 [shape=box label="Exit block"]; + 246 [shape=box label="Exit when branch result"]; + 247 [shape=box label="Exit when"]; + 248 [shape=box label="Access variable R|/b|"]; + 249 [shape=box label="Function call: R|/b|.#()"]; + 250 [shape=box label="Enter when"]; + 251 [shape=box label="Enter when branch condition "]; + 252 [shape=box label="Access variable R|/a|"]; + 253 [shape=box label="Access variable R|/b|"]; + 254 [shape=box label="Operator ==="]; + 255 [shape=box label="Exit when branch condition"]; + 256 [shape=box label="Enter block"]; + 257 [shape=box label="Access variable R|/b|"]; + 258 [shape=box label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 259 [shape=box label="Exit block"]; + 260 [shape=box label="Exit when branch result"]; + 261 [shape=box label="Enter when branch condition else"]; + 262 [shape=box label="Exit when branch condition"]; + 263 [shape=box label="Enter block"]; + 264 [shape=box label="Exit block"]; + 265 [shape=box label="Exit when branch result"]; + 266 [shape=box label="Exit when"]; + 267 [shape=box label="Access variable R|/b|"]; + 268 [shape=box label="Function call: R|/b|.#()"]; + 269 [shape=box label="Enter when"]; + 270 [shape=box label="Enter when branch condition "]; + 271 [shape=box label="Access variable R|/b|"]; + 272 [shape=box label="Access variable R|/a|"]; + 273 [shape=box label="Operator =="]; + 274 [shape=box label="Exit when branch condition"]; + 275 [shape=box label="Enter block"]; + 276 [shape=box label="Access variable R|/b|"]; + 277 [shape=box label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 278 [shape=box label="Exit block"]; + 279 [shape=box label="Exit when branch result"]; + 280 [shape=box label="Enter when branch condition else"]; + 281 [shape=box label="Exit when branch condition"]; + 282 [shape=box label="Enter block"]; + 283 [shape=box label="Exit block"]; + 284 [shape=box label="Exit when branch result"]; + 285 [shape=box label="Exit when"]; + 286 [shape=box label="Access variable R|/b|"]; + 287 [shape=box label="Function call: R|/b|.#()"]; + 288 [shape=box label="Enter when"]; + 289 [shape=box label="Enter when branch condition "]; + 290 [shape=box label="Access variable R|/b|"]; + 291 [shape=box label="Access variable R|/a|"]; + 292 [shape=box label="Operator ==="]; + 293 [shape=box label="Exit when branch condition"]; + 294 [shape=box label="Enter block"]; + 295 [shape=box label="Access variable R|/b|"]; + 296 [shape=box label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 297 [shape=box label="Exit block"]; + 298 [shape=box label="Exit when branch result"]; + 299 [shape=box label="Enter when branch condition else"]; + 300 [shape=box label="Exit when branch condition"]; + 301 [shape=box label="Enter block"]; + 302 [shape=box label="Exit block"]; + 303 [shape=box label="Exit when branch result"]; + 304 [shape=box label="Exit when"]; + 305 [shape=box label="Access variable R|/b|"]; + 306 [shape=box label="Function call: R|/b|.#()"]; + 307 [shape=box label="Exit block"]; + 308 [shape=box label="Exit function test_9"]; + + 229 -> {230}; + 230 -> {231}; + 231 -> {232}; + 232 -> {233}; + 233 -> {234}; + 234 -> {235}; + 235 -> {236}; + 236 -> {237 242}; + 237 -> {238}; + 238 -> {239}; + 239 -> {240}; + 240 -> {241}; + 241 -> {247}; + 242 -> {243}; + 243 -> {244}; + 244 -> {245}; + 245 -> {246}; + 246 -> {247}; + 247 -> {248}; + 248 -> {249}; + 249 -> {250}; + 250 -> {251}; + 251 -> {252}; + 252 -> {253}; + 253 -> {254}; + 254 -> {255}; + 255 -> {256 261}; + 256 -> {257}; + 257 -> {258}; + 258 -> {259}; + 259 -> {260}; + 260 -> {266}; + 261 -> {262}; + 262 -> {263}; + 263 -> {264}; + 264 -> {265}; + 265 -> {266}; + 266 -> {267}; + 267 -> {268}; + 268 -> {269}; + 269 -> {270}; + 270 -> {271}; + 271 -> {272}; + 272 -> {273}; + 273 -> {274}; + 274 -> {275 280}; + 275 -> {276}; + 276 -> {277}; + 277 -> {278}; + 278 -> {279}; + 279 -> {285}; + 280 -> {281}; + 281 -> {282}; + 282 -> {283}; + 283 -> {284}; + 284 -> {285}; + 285 -> {286}; + 286 -> {287}; + 287 -> {288}; + 288 -> {289}; + 289 -> {290}; + 290 -> {291}; + 291 -> {292}; + 292 -> {293}; + 293 -> {294 299}; + 294 -> {295}; + 295 -> {296}; + 296 -> {297}; + 297 -> {298}; + 298 -> {304}; + 299 -> {300}; + 300 -> {301}; + 301 -> {302}; + 302 -> {303}; + 303 -> {304}; + 304 -> {305}; + 305 -> {306}; + 306 -> {307}; + 307 -> {308}; +} + +subgraph test_10 { + 309 [shape=box label="Enter function test_10"]; + 310 [shape=box label="Enter block"]; + 311 [shape=box label="Enter when"]; + 312 [shape=box label="Enter when branch condition "]; + 313 [shape=box label="Access variable R|/a|"]; + 314 [shape=box label="Access variable R|/b|"]; + 315 [shape=box label="Operator =="]; + 316 [shape=box label="Exit when branch condition"]; + 317 [shape=box label="Enter block"]; + 318 [shape=box label="Access variable R|/b|"]; + 319 [shape=box label="Function call: R|/b|.#()"]; + 320 [shape=box label="Exit block"]; + 321 [shape=box label="Exit when branch result"]; + 322 [shape=box label="Enter when branch condition else"]; + 323 [shape=box label="Exit when branch condition"]; + 324 [shape=box label="Enter block"]; + 325 [shape=box label="Exit block"]; + 326 [shape=box label="Exit when branch result"]; + 327 [shape=box label="Exit when"]; + 328 [shape=box label="Access variable R|/b|"]; + 329 [shape=box label="Function call: R|/b|.#()"]; + 330 [shape=box label="Enter when"]; + 331 [shape=box label="Enter when branch condition "]; + 332 [shape=box label="Access variable R|/a|"]; + 333 [shape=box label="Access variable R|/b|"]; + 334 [shape=box label="Operator ==="]; + 335 [shape=box label="Exit when branch condition"]; + 336 [shape=box label="Enter block"]; + 337 [shape=box label="Access variable R|/b|"]; + 338 [shape=box label="Function call: R|/b|.#()"]; + 339 [shape=box label="Exit block"]; + 340 [shape=box label="Exit when branch result"]; + 341 [shape=box label="Enter when branch condition else"]; + 342 [shape=box label="Exit when branch condition"]; + 343 [shape=box label="Enter block"]; + 344 [shape=box label="Exit block"]; + 345 [shape=box label="Exit when branch result"]; + 346 [shape=box label="Exit when"]; + 347 [shape=box label="Access variable R|/b|"]; + 348 [shape=box label="Function call: R|/b|.#()"]; + 349 [shape=box label="Enter when"]; + 350 [shape=box label="Enter when branch condition "]; + 351 [shape=box label="Access variable R|/b|"]; + 352 [shape=box label="Access variable R|/a|"]; + 353 [shape=box label="Operator =="]; + 354 [shape=box label="Exit when branch condition"]; + 355 [shape=box label="Enter block"]; + 356 [shape=box label="Access variable R|/b|"]; + 357 [shape=box label="Function call: R|/b|.#()"]; + 358 [shape=box label="Exit block"]; + 359 [shape=box label="Exit when branch result"]; + 360 [shape=box label="Enter when branch condition else"]; + 361 [shape=box label="Exit when branch condition"]; + 362 [shape=box label="Enter block"]; + 363 [shape=box label="Exit block"]; + 364 [shape=box label="Exit when branch result"]; + 365 [shape=box label="Exit when"]; + 366 [shape=box label="Access variable R|/b|"]; + 367 [shape=box label="Function call: R|/b|.#()"]; + 368 [shape=box label="Enter when"]; + 369 [shape=box label="Enter when branch condition "]; + 370 [shape=box label="Access variable R|/b|"]; + 371 [shape=box label="Access variable R|/a|"]; + 372 [shape=box label="Operator ==="]; + 373 [shape=box label="Exit when branch condition"]; + 374 [shape=box label="Enter block"]; + 375 [shape=box label="Access variable R|/b|"]; + 376 [shape=box label="Function call: R|/b|.#()"]; + 377 [shape=box label="Exit block"]; + 378 [shape=box label="Exit when branch result"]; + 379 [shape=box label="Enter when branch condition else"]; + 380 [shape=box label="Exit when branch condition"]; + 381 [shape=box label="Enter block"]; + 382 [shape=box label="Exit block"]; + 383 [shape=box label="Exit when branch result"]; + 384 [shape=box label="Exit when"]; + 385 [shape=box label="Access variable R|/b|"]; + 386 [shape=box label="Function call: R|/b|.#()"]; + 387 [shape=box label="Exit block"]; + 388 [shape=box label="Exit function test_10"]; + + 309 -> {310}; + 310 -> {311}; + 311 -> {312}; + 312 -> {313}; + 313 -> {314}; + 314 -> {315}; + 315 -> {316}; + 316 -> {317 322}; + 317 -> {318}; + 318 -> {319}; + 319 -> {320}; + 320 -> {321}; + 321 -> {327}; + 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 -> {336 341}; + 336 -> {337}; + 337 -> {338}; + 338 -> {339}; + 339 -> {340}; + 340 -> {346}; + 341 -> {342}; + 342 -> {343}; + 343 -> {344}; + 344 -> {345}; + 345 -> {346}; + 346 -> {347}; + 347 -> {348}; + 348 -> {349}; + 349 -> {350}; + 350 -> {351}; + 351 -> {352}; + 352 -> {353}; + 353 -> {354}; + 354 -> {355 360}; + 355 -> {356}; + 356 -> {357}; + 357 -> {358}; + 358 -> {359}; + 359 -> {365}; + 360 -> {361}; + 361 -> {362}; + 362 -> {363}; + 363 -> {364}; + 364 -> {365}; + 365 -> {366}; + 366 -> {367}; + 367 -> {368}; + 368 -> {369}; + 369 -> {370}; + 370 -> {371}; + 371 -> {372}; + 372 -> {373}; + 373 -> {374 379}; + 374 -> {375}; + 375 -> {376}; + 376 -> {377}; + 377 -> {378}; + 378 -> {384}; + 379 -> {380}; + 380 -> {381}; + 381 -> {382}; + 382 -> {383}; + 383 -> {384}; + 384 -> {385}; + 385 -> {386}; + 386 -> {387}; + 387 -> {388}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt new file mode 100644 index 00000000000..75932b33f5b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt @@ -0,0 +1,119 @@ +interface A { + fun foo() + fun getA(): A +} + +interface MyData{ + val s: Int + + fun fs(): Int +} + +interface Q { + val data: MyData? + + fun fdata(): MyData? +} + +// ------------------------------------------------------------------- + +fun test_1(x: A?) { + if (x != null) { + x.foo() + } else { + x.foo() + } + x.foo() +} + +fun test_2(x: A?) { + if (x == null) { + x.foo() + } else { + x.foo() + } + x.foo() +} + +fun test_3(x: A?) { + x ?: return + x.foo() +} + +fun test_4(x: A?) { + if (x?.getA() == null) return + x.foo() +} + +fun test_5(q: Q?) { + if (q?.data?.s?.inc() != null) { + q.data + q.data.s + q.data.s.inc() + } +} + +fun test_6(q: Q?) { + q?.data?.s?.inc() ?: return + q.data + q.data.s + q.data.s.inc() +} + +fun test_7(q: Q?) { + if (q?.fdata()?.fs()?.inc() != null) { + q.fdata() // good + q.fdata().fs() // bad + q.fdata().fs().inc() // bad + } +} + +fun test_8(b: Boolean?) { + if (b == true) { + b.not() + } +} + +fun test_9(a: Int, b: Int?) { + if (a == b) { + b.inc() + } + b.inc() + + if (a === b) { + b.inc() + } + b.inc() + + if (b == a) { + b.inc() + } + b.inc() + + if (b === a) { + b.inc() + } + b.inc() +} + +fun test_10(a: Int?, b: Int?) { + if (a == b) { + b.inc() + } + b.inc() + + if (a === b) { + b.inc() + } + b.inc() + + if (b == a) { + b.inc() + } + b.inc() + + if (b === a) { + b.inc() + } + b.inc() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.txt b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.txt new file mode 100644 index 00000000000..c3cd926367e --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.txt @@ -0,0 +1,192 @@ +FILE: nullability.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + public abstract fun getA(): R|A| + + } + public abstract interface MyData : R|kotlin/Any| { + public abstract val s: R|kotlin/Int| + public get(): R|kotlin/Int| + + public abstract fun fs(): R|kotlin/Int| + + } + public abstract interface Q : R|kotlin/Any| { + public abstract val data: R|MyData?| + public get(): R|MyData?| + + public abstract fun fdata(): R|MyData?| + + } + public final fun test_1(x: R|A?|): R|kotlin/Unit| { + when () { + !=(R|/x|, Null(null)) -> { + R|/x|.R|/A.foo|() + } + else -> { + R|/x|.#() + } + } + + R|/x|.#() + } + public final fun test_2(x: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/x|, Null(null)) -> { + R|/x|.#() + } + else -> { + R|/x|.R|/A.foo|() + } + } + + R|/x|.#() + } + public final fun test_3(x: R|A?|): R|kotlin/Unit| { + when (lval : R|A?| = R|/x|) { + ==($subj$, Null(null)) -> { + ^test_3 Unit + } + else -> { + R|/|! + } + } + + R|/x|.R|/A.foo|() + } + public final fun test_4(x: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/x|?.R|/A.getA|(), Null(null)) -> { + ^test_4 Unit + } + else -> { + } + } + + R|/x|.R|/A.foo|() + } + public final fun test_5(q: R|Q?|): R|kotlin/Unit| { + when () { + !=(R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|(), Null(null)) -> { + R|/q|.R|/Q.data| + R|/q|.R|/Q.data|.R|/MyData.s| + R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|() + } + else -> { + } + } + + } + public final fun test_6(q: R|Q?|): R|kotlin/Unit| { + when (lval : R|kotlin/Int| = R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()) { + ==($subj$, Null(null)) -> { + ^test_6 Unit + } + else -> { + R|/|! + } + } + + R|/q|.R|/Q.data| + R|/q|.R|/Q.data|.R|/MyData.s| + R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|() + } + public final fun test_7(q: R|Q?|): R|kotlin/Unit| { + when () { + !=(R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()?.R|kotlin/Int.inc|(), Null(null)) -> { + R|/q|.R|/Q.fdata|() + R|/q|.R|/Q.fdata|().#() + R|/q|.R|/Q.fdata|().#().#() + } + else -> { + } + } + + } + public final fun test_8(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + ==(R|/b|, Boolean(true)) -> { + R|/b|.R|kotlin/Boolean.not|() + } + else -> { + } + } + + } + public final fun test_9(a: R|kotlin/Int|, b: R|kotlin/Int?|): R|kotlin/Unit| { + when () { + ==(R|/a|, R|/b|) -> { + R|/b|.R|kotlin/Int.inc|() + } + else -> { + } + } + + R|/b|.#() + when () { + ===(R|/a|, R|/b|) -> { + R|/b|.R|kotlin/Int.inc|() + } + else -> { + } + } + + R|/b|.#() + when () { + ==(R|/b|, R|/a|) -> { + R|/b|.R|kotlin/Int.inc|() + } + else -> { + } + } + + R|/b|.#() + when () { + ===(R|/b|, R|/a|) -> { + R|/b|.R|kotlin/Int.inc|() + } + else -> { + } + } + + R|/b|.#() + } + public final fun test_10(a: R|kotlin/Int?|, b: R|kotlin/Int?|): R|kotlin/Unit| { + when () { + ==(R|/a|, R|/b|) -> { + R|/b|.#() + } + else -> { + } + } + + R|/b|.#() + when () { + ===(R|/a|, R|/b|) -> { + R|/b|.#() + } + else -> { + } + } + + R|/b|.#() + when () { + ==(R|/b|, R|/a|) -> { + R|/b|.#() + } + else -> { + } + } + + R|/b|.#() + when () { + ===(R|/b|, R|/a|) -> { + R|/b|.#() + } + else -> { + } + } + + R|/b|.#() + } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/returns.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/returns.cfg.dot new file mode 100644 index 00000000000..b2caca4095e --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/returns.cfg.dot @@ -0,0 +1,273 @@ +digraph returns_kt { +subgraph test_0 { + 0 [shape=box label="Enter function test_0"]; + 1 [shape=box label="Enter block"]; + 2 [shape=box label="Enter when"]; + 3 [shape=box label="Enter when branch condition "]; + 4 [shape=box label="Access variable R|/x|"]; + 5 [shape=box label="Type operator: x is String"]; + 6 [shape=box label="Exit when branch condition"]; + 7 [shape=box label="Enter block"]; + 8 [shape=box label="Access variable R|/x|"]; + 9 [shape=box label="Access variable R|kotlin/String.length|"]; + 10 [shape=box label="Exit block"]; + 11 [shape=box label="Exit when branch result"]; + 12 [shape=box label="Enter when branch condition else"]; + 13 [shape=box label="Exit when branch condition"]; + 14 [shape=box label="Enter block"]; + 15 [shape=box label="Exit block"]; + 16 [shape=box label="Exit when branch result"]; + 17 [shape=box label="Exit when"]; + 18 [shape=box label="Access variable R|/x|"]; + 19 [shape=box label="Access variable #"]; + 20 [shape=box label="Exit block"]; + 21 [shape=box label="Exit function test_0"]; + + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7 12}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {17}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; +} + +subgraph test_1 { + 22 [shape=box label="Enter function test_1"]; + 23 [shape=box label="Enter block"]; + 24 [shape=box label="Enter when"]; + 25 [shape=box label="Enter when branch condition "]; + 26 [shape=box label="Access variable R|/x|"]; + 27 [shape=box label="Type operator: x is String"]; + 28 [shape=box label="Exit when branch condition"]; + 29 [shape=box label="Enter block"]; + 30 [shape=box label="Access variable R|/x|"]; + 31 [shape=box label="Access variable R|kotlin/String.length|"]; + 32 [shape=box label="Exit block"]; + 33 [shape=box label="Exit when branch result"]; + 34 [shape=box label="Enter when branch condition else"]; + 35 [shape=box label="Exit when branch condition"]; + 36 [shape=box label="Enter block"]; + 37 [shape=box label="Jump: ^test_1 Unit"]; + 38 [shape=box label="Stub[DEAD]"]; + 39 [shape=box label="Exit block[DEAD]"]; + 40 [shape=box label="Exit when branch result[DEAD]"]; + 41 [shape=box label="Exit when"]; + 42 [shape=box label="Access variable R|/x|"]; + 43 [shape=box label="Access variable R|kotlin/String.length|"]; + 44 [shape=box label="Exit block"]; + 45 [shape=box label="Exit function test_1"]; + + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29 34}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {41}; + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {45}; + 37 -> {38} [style=dotted]; + 38 -> {39} [style=dotted]; + 39 -> {40} [style=dotted]; + 40 -> {41} [style=dotted]; + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {45}; +} + +subgraph foo { + 46 [shape=box label="Enter function foo"]; + 47 [shape=box label="Exit function foo"]; + + 46 -> {47}; +} + +subgraph bar { + 48 [shape=box label="Enter function bar"]; + 49 [shape=box label="Exit function bar"]; + + 48 -> {49}; +} + +subgraph baz { + 50 [shape=box label="Enter function baz"]; + 51 [shape=box label="Exit function baz"]; + + 50 -> {51}; +} + +subgraph test_2 { + 52 [shape=box label="Enter function test_2"]; + 53 [shape=box label="Enter block"]; + 54 [shape=box label="Enter when"]; + 55 [shape=box label="Enter when branch condition "]; + 56 [shape=box label="Access variable R|/x|"]; + 57 [shape=box label="Type operator: x is B"]; + 58 [shape=box label="Exit when branch condition"]; + 59 [shape=box label="Enter block"]; + 60 [shape=box label="Access variable R|/x|"]; + 61 [shape=box label="Function call: R|/x|.R|/B.bar|()"]; + 62 [shape=box label="Exit block"]; + 63 [shape=box label="Exit when branch result"]; + 64 [shape=box label="Enter when branch condition "]; + 65 [shape=box label="Access variable R|/x|"]; + 66 [shape=box label="Type operator: x is C"]; + 67 [shape=box label="Exit when branch condition"]; + 68 [shape=box label="Enter block"]; + 69 [shape=box label="Access variable R|/x|"]; + 70 [shape=box label="Function call: R|/x|.R|/C.baz|()"]; + 71 [shape=box label="Exit block"]; + 72 [shape=box label="Exit when branch result"]; + 73 [shape=box label="Enter when branch condition else"]; + 74 [shape=box label="Exit when branch condition"]; + 75 [shape=box label="Enter block"]; + 76 [shape=box label="Jump: ^test_2 Unit"]; + 77 [shape=box label="Stub[DEAD]"]; + 78 [shape=box label="Exit block[DEAD]"]; + 79 [shape=box label="Exit when branch result[DEAD]"]; + 80 [shape=box label="Exit when"]; + 81 [shape=box label="Access variable R|/x|"]; + 82 [shape=box label="Function call: R|/x|.R|/A.foo|()"]; + 83 [shape=box label="Access variable R|/x|"]; + 84 [shape=box label="Function call: R|/x|.#()"]; + 85 [shape=box label="Access variable R|/x|"]; + 86 [shape=box label="Function call: R|/x|.#()"]; + 87 [shape=box label="Exit block"]; + 88 [shape=box label="Exit function test_2"]; + + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59 64}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; + 63 -> {80}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68 73}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {80}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {88}; + 76 -> {77} [style=dotted]; + 77 -> {78} [style=dotted]; + 78 -> {79} [style=dotted]; + 79 -> {80} [style=dotted]; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; +} + +subgraph test_3 { + 89 [shape=box label="Enter function test_3"]; + 90 [shape=box label="Enter block"]; + 91 [shape=box label="Enter when"]; + 92 [shape=box label="Enter when branch condition "]; + 93 [shape=box label="Access variable R|/x|"]; + 94 [shape=box label="Type operator: x is B"]; + 95 [shape=box label="Exit when branch condition"]; + 96 [shape=box label="Enter block"]; + 97 [shape=box label="Access variable R|/x|"]; + 98 [shape=box label="Function call: R|/x|.R|/B.bar|()"]; + 99 [shape=box label="Exit block"]; + 100 [shape=box label="Exit when branch result"]; + 101 [shape=box label="Enter when branch condition "]; + 102 [shape=box label="Access variable R|/x|"]; + 103 [shape=box label="Type operator: x is C"]; + 104 [shape=box label="Exit when branch condition"]; + 105 [shape=box label="Enter block"]; + 106 [shape=box label="Access variable R|/x|"]; + 107 [shape=box label="Function call: R|/x|.R|/C.baz|()"]; + 108 [shape=box label="Exit block"]; + 109 [shape=box label="Exit when branch result"]; + 110 [shape=box label="Enter when branch condition else"]; + 111 [shape=box label="Exit when branch condition"]; + 112 [shape=box label="Enter block"]; + 113 [shape=box label="Exit block"]; + 114 [shape=box label="Exit when branch result"]; + 115 [shape=box label="Exit when"]; + 116 [shape=box label="Access variable R|/x|"]; + 117 [shape=box label="Function call: R|/x|.#()"]; + 118 [shape=box label="Access variable R|/x|"]; + 119 [shape=box label="Function call: R|/x|.#()"]; + 120 [shape=box label="Access variable R|/x|"]; + 121 [shape=box label="Function call: R|/x|.#()"]; + 122 [shape=box label="Exit block"]; + 123 [shape=box label="Exit function test_3"]; + + 89 -> {90}; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {94}; + 94 -> {95}; + 95 -> {96 101}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {100}; + 100 -> {115}; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; + 104 -> {105 110}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {115}; + 110 -> {111}; + 111 -> {112}; + 112 -> {113}; + 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122}; + 122 -> {123}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/returns.kt b/compiler/fir/resolve/testData/resolve/smartcasts/returns.kt new file mode 100644 index 00000000000..dea1b5fb25c --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/returns.kt @@ -0,0 +1,50 @@ +fun test_0(x: Any) { + if (x is String) { + x.length + } else { + + } + x.length +} + +fun test_1(x: Any) { + if (x is String) { + x.length + } else { + return + } + x.length +} + +interface A { + fun foo() +} + +interface B : A { + fun bar() +} + +interface C : A { + fun baz() +} + +fun test_2(x: Any) { + when { + x is B -> x.bar() + x is C -> x.baz() + else -> return + } + x.foo() + x.bar() + x.baz() +} + +fun test_3(x: Any) { + when { + x is B -> x.bar() + x is C -> x.baz() + } + x.foo() + x.bar() + x.baz() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/returns.txt b/compiler/fir/resolve/testData/resolve/smartcasts/returns.txt new file mode 100644 index 00000000000..970097b299b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/returns.txt @@ -0,0 +1,69 @@ +FILE: returns.kt + public final fun test_0(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|kotlin/String|) -> { + R|/x|.R|kotlin/String.length| + } + else -> { + } + } + + R|/x|.# + } + public final fun test_1(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|kotlin/String|) -> { + R|/x|.R|kotlin/String.length| + } + else -> { + ^test_1 Unit + } + } + + R|/x|.R|kotlin/String.length| + } + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + } + public abstract interface B : R|A| { + public abstract fun bar(): R|kotlin/Unit| + + } + public abstract interface C : R|A| { + public abstract fun baz(): R|kotlin/Unit| + + } + public final fun test_2(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|B|) -> { + R|/x|.R|/B.bar|() + } + (R|/x| is R|C|) -> { + R|/x|.R|/C.baz|() + } + else -> { + ^test_2 Unit + } + } + + R|/x|.R|/A.foo|() + R|/x|.#() + R|/x|.#() + } + public final fun test_3(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|B|) -> { + R|/x|.R|/B.bar|() + } + (R|/x| is R|C|) -> { + R|/x|.R|/C.baz|() + } + else -> { + } + } + + R|/x|.#() + R|/x|.#() + R|/x|.#() + } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.cfg.dot new file mode 100644 index 00000000000..84c328c194d --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.cfg.dot @@ -0,0 +1,161 @@ +digraph simpleIf_kt { +subgraph test_1 { + 0 [shape=box label="Enter function test_1"]; + 1 [shape=box label="Enter block"]; + 2 [shape=box label="Enter when"]; + 3 [shape=box label="Enter when branch condition "]; + 4 [shape=box label="Access variable R|/x|"]; + 5 [shape=box label="Type operator: x is String"]; + 6 [shape=box label="Exit when branch condition"]; + 7 [shape=box label="Enter block"]; + 8 [shape=box label="Access variable R|/x|"]; + 9 [shape=box label="Access variable R|kotlin/String.length|"]; + 10 [shape=box label="Exit block"]; + 11 [shape=box label="Exit when branch result"]; + 12 [shape=box label="Enter when branch condition else"]; + 13 [shape=box label="Exit when branch condition"]; + 14 [shape=box label="Enter block"]; + 15 [shape=box label="Exit block"]; + 16 [shape=box label="Exit when branch result"]; + 17 [shape=box label="Exit when"]; + 18 [shape=box label="Access variable R|/x|"]; + 19 [shape=box label="Access variable #"]; + 20 [shape=box label="Exit block"]; + 21 [shape=box label="Exit function test_1"]; + + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7 12}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {17}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; +} + +subgraph test_2 { + 22 [shape=box label="Enter function test_2"]; + 23 [shape=box label="Enter block"]; + 24 [shape=box label="Access variable R|/x|"]; + 25 [shape=box label="Type operator: x is String"]; + 26 [shape=box label="Variable declaration: lval b: R|kotlin/Boolean|"]; + 27 [shape=box label="Enter when"]; + 28 [shape=box label="Enter when branch condition "]; + 29 [shape=box label="Access variable R|/b|"]; + 30 [shape=box label="Exit when branch condition"]; + 31 [shape=box label="Enter block"]; + 32 [shape=box label="Access variable R|/x|"]; + 33 [shape=box label="Access variable R|kotlin/String.length|"]; + 34 [shape=box label="Exit block"]; + 35 [shape=box label="Exit when branch result"]; + 36 [shape=box label="Enter when branch condition else"]; + 37 [shape=box label="Exit when branch condition"]; + 38 [shape=box label="Enter block"]; + 39 [shape=box label="Exit block"]; + 40 [shape=box label="Exit when branch result"]; + 41 [shape=box label="Exit when"]; + 42 [shape=box label="Access variable R|/x|"]; + 43 [shape=box label="Access variable #"]; + 44 [shape=box label="Exit block"]; + 45 [shape=box label="Exit function test_2"]; + + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 29 -> {30}; + 30 -> {31 36}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {41}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {45}; +} + +subgraph test_3 { + 46 [shape=box label="Enter function test_3"]; + 47 [shape=box label="Enter block"]; + 48 [shape=box label="Enter when"]; + 49 [shape=box label="Enter when branch condition "]; + 50 [shape=box label="Access variable R|/x|"]; + 51 [shape=box label="Type operator: x !is String"]; + 52 [shape=box label="Exit when branch condition"]; + 53 [shape=box label="Enter block"]; + 54 [shape=box label="Exit block"]; + 55 [shape=box label="Exit when branch result"]; + 56 [shape=box label="Enter when branch condition "]; + 57 [shape=box label="Access variable R|/x|"]; + 58 [shape=box label="Type operator: x !is Int"]; + 59 [shape=box label="Exit when branch condition"]; + 60 [shape=box label="Enter block"]; + 61 [shape=box label="Exit block"]; + 62 [shape=box label="Exit when branch result"]; + 63 [shape=box label="Enter when branch condition else"]; + 64 [shape=box label="Exit when branch condition"]; + 65 [shape=box label="Enter block"]; + 66 [shape=box label="Access variable R|/x|"]; + 67 [shape=box label="Access variable R|kotlin/String.length|"]; + 68 [shape=box label="Access variable R|/x|"]; + 69 [shape=box label="Function call: R|/x|.R|kotlin/Int.inc|()"]; + 70 [shape=box label="Exit block"]; + 71 [shape=box label="Exit when branch result"]; + 72 [shape=box label="Exit when"]; + 73 [shape=box label="Exit block"]; + 74 [shape=box label="Exit function test_3"]; + + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53 56}; + 53 -> {54}; + 54 -> {55}; + 55 -> {72}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60 63}; + 60 -> {61}; + 61 -> {62}; + 62 -> {72}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt b/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt new file mode 100644 index 00000000000..d971fd64bea --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt @@ -0,0 +1,25 @@ +fun test_1(x: Any) { + if (x is String) { + x.length + } + x.length +} + +fun test_2(x: Any) { + val b = x is String + if (b) { + x.length + } + x.length +} + +fun test_3(x: Any) { + when { + x !is String -> {} + x !is Int -> {} + else -> { + x.length + x.inc() + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.txt b/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.txt new file mode 100644 index 00000000000..97ecd6f97a4 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.txt @@ -0,0 +1,37 @@ +FILE: simpleIf.kt + public final fun test_1(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| is R|kotlin/String|) -> { + R|/x|.R|kotlin/String.length| + } + else -> { + } + } + + R|/x|.# + } + public final fun test_2(x: R|kotlin/Any|): R|kotlin/Unit| { + lval b: R|kotlin/Boolean| = (R|/x| is R|kotlin/String|) + when () { + R|/b| -> { + R|/x|.R|kotlin/String.length| + } + else -> { + } + } + + R|/x|.# + } + public final fun test_3(x: R|kotlin/Any|): R|kotlin/Unit| { + when () { + (R|/x| !is R|kotlin/String|) -> { + } + (R|/x| !is R|kotlin/Int|) -> { + } + else -> { + R|/x|.R|kotlin/String.length| + R|/x|.R|kotlin/Int.inc|() + } + } + + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java index c618bbe61ca..a933584c1e5 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java @@ -17,60 +17,106 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@TestMetadata("compiler/fir/resolve/testData/resolve/cfg") -@TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + @TestMetadata("compiler/fir/resolve/testData/resolve/cfg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Cfg extends AbstractFirCfgBuildingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInCfg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/cfg"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("binaryOperations.kt") + public void testBinaryOperations() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt"); + } + + @TestMetadata("complex.kt") + public void testComplex() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/complex.kt"); + } + + @TestMetadata("initBlock.kt") + public void testInitBlock() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/initBlock.kt"); + } + + @TestMetadata("jumps.kt") + public void testJumps() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/jumps.kt"); + } + + @TestMetadata("loops.kt") + public void testLoops() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/loops.kt"); + } + + @TestMetadata("propertiesAndInitBlocks.kt") + public void testPropertiesAndInitBlocks() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/simple.kt"); + } + + @TestMetadata("tryCatch.kt") + public void testTryCatch() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt"); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/when.kt"); + } } - public void testAllFilesPresentInCfg() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/cfg"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); - } + @TestMetadata("compiler/fir/resolve/testData/resolve/smartcasts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Smartcasts extends AbstractFirCfgBuildingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } - @TestMetadata("binaryOperations.kt") - public void testBinaryOperations() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt"); - } + public void testAllFilesPresentInSmartcasts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/smartcasts"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + } - @TestMetadata("complex.kt") - public void testComplex() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/complex.kt"); - } + @TestMetadata("booleanOperators.kt") + public void testBooleanOperators() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/booleanOperators.kt"); + } - @TestMetadata("initBlock.kt") - public void testInitBlock() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/initBlock.kt"); - } + @TestMetadata("casts.kt") + public void testCasts() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/casts.kt"); + } - @TestMetadata("jumps.kt") - public void testJumps() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/jumps.kt"); - } + @TestMetadata("equalsAndIdentity.kt") + public void testEqualsAndIdentity() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt"); + } - @TestMetadata("loops.kt") - public void testLoops() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/loops.kt"); - } + @TestMetadata("nullability.kt") + public void testNullability() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt"); + } - @TestMetadata("propertiesAndInitBlocks.kt") - public void testPropertiesAndInitBlocks() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt"); - } + @TestMetadata("returns.kt") + public void testReturns() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/returns.kt"); + } - @TestMetadata("simple.kt") - public void testSimple() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/simple.kt"); - } - - @TestMetadata("tryCatch.kt") - public void testTryCatch() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt"); - } - - @TestMetadata("when.kt") - public void testWhen() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/cfg/when.kt"); + @TestMetadata("simpleIf.kt") + public void testSimpleIf() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt"); + } } } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index 71c1c7f8e08..82d3c0900d7 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -26,7 +26,7 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase { } public void testAllFilesPresentInResolve() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true, "stdlib", "cfg"); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true, "stdlib", "cfg", "smartcasts"); } @TestMetadata("cast.kt") diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index 78a789b12dd..23d4e7ca196 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -439,7 +439,7 @@ fun main(args: Array) { testGroup("compiler/fir/resolve/tests", "compiler/fir/resolve/testData") { testClass { - model("resolve", pattern = KT_WITHOUT_DOTS_IN_NAME, excludeDirs = listOf("stdlib", "cfg")) + model("resolve", pattern = KT_WITHOUT_DOTS_IN_NAME, excludeDirs = listOf("stdlib", "cfg", "smartcasts")) } testClass { @@ -448,6 +448,7 @@ fun main(args: Array) { testClass { model("resolve/cfg", pattern = KT_WITHOUT_DOTS_IN_NAME) + model("resolve/smartcasts", pattern = KT_WITHOUT_DOTS_IN_NAME) } }