diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index 1f26fa6a3f0..d060b97196f 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -3657,6 +3657,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis public void testWhen() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.kt"); } + + @Test + @TestMetadata("whenSubjectExpression.kt") + public void testWhenSubjectExpression() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 7fe64522d07..4d07376ac64 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -3241,6 +3241,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract public void testWhen() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.kt"); } + + @TestMetadata("whenSubjectExpression.kt") + public void testWhenSubjectExpression() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt"); + } } @TestMetadata("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas") diff --git a/compiler/fir/analysis-tests/testData/resolve/exhaustiveness/positive/exhaustiveWhenAndDNNType.dot b/compiler/fir/analysis-tests/testData/resolve/exhaustiveness/positive/exhaustiveWhenAndDNNType.dot index 6bfb077ae0f..490ae8546d4 100644 --- a/compiler/fir/analysis-tests/testData/resolve/exhaustiveness/positive/exhaustiveWhenAndDNNType.dot +++ b/compiler/fir/analysis-tests/testData/resolve/exhaustiveness/positive/exhaustiveWhenAndDNNType.dot @@ -66,43 +66,45 @@ digraph exhaustiveWhenAndDNNType_kt { subgraph cluster_9 { color=blue 22 [label="Enter when branch condition "]; - 23 [label="Access qualifier /SomeEnum"]; - 24 [label="Access variable R|/SomeEnum.A1|"]; - 25 [label="Equality operator =="]; - 26 [label="Exit when branch condition"]; + 23 [label="Exit $subj"]; + 24 [label="Access qualifier /SomeEnum"]; + 25 [label="Access variable R|/SomeEnum.A1|"]; + 26 [label="Equality operator =="]; + 27 [label="Exit when branch condition"]; } subgraph cluster_10 { color=blue - 27 [label="Enter when branch condition "]; - 28 [label="Access qualifier /SomeEnum"]; - 29 [label="Access variable R|/SomeEnum.A2|"]; - 30 [label="Equality operator =="]; - 31 [label="Exit when branch condition"]; + 28 [label="Enter when branch condition "]; + 29 [label="Exit $subj"]; + 30 [label="Access qualifier /SomeEnum"]; + 31 [label="Access variable R|/SomeEnum.A2|"]; + 32 [label="Equality operator =="]; + 33 [label="Exit when branch condition"]; } - 32 [label="Enter when branch result"]; + 34 [label="Enter when branch result"]; subgraph cluster_11 { color=blue - 33 [label="Enter block"]; - 34 [label="Function call: R|/B.B|()"]; - 35 [label="Exit block"]; + 35 [label="Enter block"]; + 36 [label="Function call: R|/B.B|()"]; + 37 [label="Exit block"]; } - 36 [label="Exit when branch result"]; - 37 [label="Enter when branch result"]; + 38 [label="Exit when branch result"]; + 39 [label="Enter when branch result"]; subgraph cluster_12 { color=blue - 38 [label="Enter block"]; - 39 [label="Function call: R|/B.B|()"]; - 40 [label="Exit block"]; + 40 [label="Enter block"]; + 41 [label="Function call: R|/B.B|()"]; + 42 [label="Exit block"]; } - 41 [label="Exit when branch result"]; - 42 [label="Exit when"]; + 43 [label="Exit when branch result"]; + 44 [label="Exit when"]; } - 43 [label="Variable declaration: lval b: R|B|"]; - 44 [label="Access variable R|/b|"]; - 45 [label="Function call: R|/takeB|(...)"]; - 46 [label="Exit block"]; + 45 [label="Variable declaration: lval b: R|B|"]; + 46 [label="Access variable R|/b|"]; + 47 [label="Function call: R|/takeB|(...)"]; + 48 [label="Exit block"]; } - 47 [label="Exit function test_1" style="filled" fillcolor=red]; + 49 [label="Exit function test_1" style="filled" fillcolor=red]; } 14 -> {15}; 15 -> {16}; @@ -116,8 +118,8 @@ digraph exhaustiveWhenAndDNNType_kt { 23 -> {24}; 24 -> {25}; 25 -> {26}; - 26 -> {37 27}; - 27 -> {28}; + 26 -> {27}; + 27 -> {39 28}; 28 -> {29}; 29 -> {30}; 30 -> {31}; @@ -126,9 +128,9 @@ digraph exhaustiveWhenAndDNNType_kt { 33 -> {34}; 34 -> {35}; 35 -> {36}; - 36 -> {42}; + 36 -> {37}; 37 -> {38}; - 38 -> {39}; + 38 -> {44}; 39 -> {40}; 40 -> {41}; 41 -> {42}; @@ -137,64 +139,66 @@ digraph exhaustiveWhenAndDNNType_kt { 44 -> {45}; 45 -> {46}; 46 -> {47}; + 47 -> {48}; + 48 -> {49}; subgraph cluster_13 { color=red - 48 [label="Enter function test_2" style="filled" fillcolor=red]; + 50 [label="Enter function test_2" style="filled" fillcolor=red]; subgraph cluster_14 { color=blue - 49 [label="Enter block"]; - 50 [label="Access qualifier /SomeEnum"]; - 51 [label="Access variable R|/SomeEnum.A1|"]; - 52 [label="Variable declaration: lval flag: R|SomeEnum|"]; + 51 [label="Enter block"]; + 52 [label="Access qualifier /SomeEnum"]; + 53 [label="Access variable R|/SomeEnum.A1|"]; + 54 [label="Variable declaration: lval flag: R|SomeEnum|"]; subgraph cluster_15 { color=blue - 53 [label="Enter when"]; - 54 [label="Access variable R|/flag|"]; - 55 [label="Check not null: R|/flag|!!"]; + 55 [label="Enter when"]; + 56 [label="Access variable R|/flag|"]; + 57 [label="Check not null: R|/flag|!!"]; subgraph cluster_16 { color=blue - 56 [label="Enter when branch condition "]; - 57 [label="Access qualifier /SomeEnum"]; - 58 [label="Access variable R|/SomeEnum.A1|"]; - 59 [label="Equality operator =="]; - 60 [label="Exit when branch condition"]; + 58 [label="Enter when branch condition "]; + 59 [label="Exit $subj"]; + 60 [label="Access qualifier /SomeEnum"]; + 61 [label="Access variable R|/SomeEnum.A1|"]; + 62 [label="Equality operator =="]; + 63 [label="Exit when branch condition"]; } subgraph cluster_17 { color=blue - 61 [label="Enter when branch condition "]; - 62 [label="Access qualifier /SomeEnum"]; - 63 [label="Access variable R|/SomeEnum.A2|"]; - 64 [label="Equality operator =="]; - 65 [label="Exit when branch condition"]; + 64 [label="Enter when branch condition "]; + 65 [label="Exit $subj"]; + 66 [label="Access qualifier /SomeEnum"]; + 67 [label="Access variable R|/SomeEnum.A2|"]; + 68 [label="Equality operator =="]; + 69 [label="Exit when branch condition"]; } - 66 [label="Enter when branch result"]; + 70 [label="Enter when branch result"]; subgraph cluster_18 { color=blue - 67 [label="Enter block"]; - 68 [label="Function call: R|/B.B|()"]; - 69 [label="Exit block"]; + 71 [label="Enter block"]; + 72 [label="Function call: R|/B.B|()"]; + 73 [label="Exit block"]; } - 70 [label="Exit when branch result"]; - 71 [label="Enter when branch result"]; + 74 [label="Exit when branch result"]; + 75 [label="Enter when branch result"]; subgraph cluster_19 { color=blue - 72 [label="Enter block"]; - 73 [label="Function call: R|/B.B|()"]; - 74 [label="Exit block"]; + 76 [label="Enter block"]; + 77 [label="Function call: R|/B.B|()"]; + 78 [label="Exit block"]; } - 75 [label="Exit when branch result"]; - 76 [label="Exit when"]; + 79 [label="Exit when branch result"]; + 80 [label="Exit when"]; } - 77 [label="Variable declaration: lval b: R|B|"]; - 78 [label="Access variable R|/b|"]; - 79 [label="Function call: R|/takeB|(...)"]; - 80 [label="Exit block"]; + 81 [label="Variable declaration: lval b: R|B|"]; + 82 [label="Access variable R|/b|"]; + 83 [label="Function call: R|/takeB|(...)"]; + 84 [label="Exit block"]; } - 81 [label="Exit function test_2" style="filled" fillcolor=red]; + 85 [label="Exit function test_2" style="filled" fillcolor=red]; } - 48 -> {49}; - 49 -> {50}; 50 -> {51}; 51 -> {52}; 52 -> {53}; @@ -205,86 +209,88 @@ digraph exhaustiveWhenAndDNNType_kt { 57 -> {58}; 58 -> {59}; 59 -> {60}; - 60 -> {71 61}; + 60 -> {61}; 61 -> {62}; 62 -> {63}; - 63 -> {64}; + 63 -> {75 64}; 64 -> {65}; 65 -> {66}; 66 -> {67}; 67 -> {68}; 68 -> {69}; 69 -> {70}; - 70 -> {76}; + 70 -> {71}; 71 -> {72}; 72 -> {73}; 73 -> {74}; - 74 -> {75}; + 74 -> {80}; 75 -> {76}; 76 -> {77}; 77 -> {78}; 78 -> {79}; 79 -> {80}; 80 -> {81}; - - subgraph cluster_20 { - color=red - 82 [label="Enter function test_3" style="filled" fillcolor=red]; - subgraph cluster_21 { - color=blue - 83 [label="Enter block"]; - 84 [label="Access qualifier /SomeEnum"]; - 85 [label="Access variable R|/SomeEnum.A1|"]; - 86 [label="Variable declaration: lval flag: R|SomeEnum|"]; - subgraph cluster_22 { - color=blue - 87 [label="Enter when"]; - 88 [label="Access variable R|/flag|"]; - subgraph cluster_23 { - color=blue - 89 [label="Enter when branch condition "]; - 90 [label="Access qualifier /SomeEnum"]; - 91 [label="Access variable R|/SomeEnum.A1|"]; - 92 [label="Equality operator =="]; - 93 [label="Exit when branch condition"]; - } - subgraph cluster_24 { - color=blue - 94 [label="Enter when branch condition "]; - 95 [label="Access qualifier /SomeEnum"]; - 96 [label="Access variable R|/SomeEnum.A2|"]; - 97 [label="Equality operator =="]; - 98 [label="Exit when branch condition"]; - } - 99 [label="Enter when branch result"]; - subgraph cluster_25 { - color=blue - 100 [label="Enter block"]; - 101 [label="Function call: R|/B.B|()"]; - 102 [label="Exit block"]; - } - 103 [label="Exit when branch result"]; - 104 [label="Enter when branch result"]; - subgraph cluster_26 { - color=blue - 105 [label="Enter block"]; - 106 [label="Function call: R|/B.B|()"]; - 107 [label="Exit block"]; - } - 108 [label="Exit when branch result"]; - 109 [label="Exit when"]; - } - 110 [label="Variable declaration: lval b: R|B|"]; - 111 [label="Access variable R|/b|"]; - 112 [label="Function call: R|/takeB|(...)"]; - 113 [label="Exit block"]; - } - 114 [label="Exit function test_3" style="filled" fillcolor=red]; - } + 81 -> {82}; 82 -> {83}; 83 -> {84}; 84 -> {85}; - 85 -> {86}; + + subgraph cluster_20 { + color=red + 86 [label="Enter function test_3" style="filled" fillcolor=red]; + subgraph cluster_21 { + color=blue + 87 [label="Enter block"]; + 88 [label="Access qualifier /SomeEnum"]; + 89 [label="Access variable R|/SomeEnum.A1|"]; + 90 [label="Variable declaration: lval flag: R|SomeEnum|"]; + subgraph cluster_22 { + color=blue + 91 [label="Enter when"]; + 92 [label="Access variable R|/flag|"]; + subgraph cluster_23 { + color=blue + 93 [label="Enter when branch condition "]; + 94 [label="Exit $subj"]; + 95 [label="Access qualifier /SomeEnum"]; + 96 [label="Access variable R|/SomeEnum.A1|"]; + 97 [label="Equality operator =="]; + 98 [label="Exit when branch condition"]; + } + subgraph cluster_24 { + color=blue + 99 [label="Enter when branch condition "]; + 100 [label="Exit $subj"]; + 101 [label="Access qualifier /SomeEnum"]; + 102 [label="Access variable R|/SomeEnum.A2|"]; + 103 [label="Equality operator =="]; + 104 [label="Exit when branch condition"]; + } + 105 [label="Enter when branch result"]; + subgraph cluster_25 { + color=blue + 106 [label="Enter block"]; + 107 [label="Function call: R|/B.B|()"]; + 108 [label="Exit block"]; + } + 109 [label="Exit when branch result"]; + 110 [label="Enter when branch result"]; + subgraph cluster_26 { + color=blue + 111 [label="Enter block"]; + 112 [label="Function call: R|/B.B|()"]; + 113 [label="Exit block"]; + } + 114 [label="Exit when branch result"]; + 115 [label="Exit when"]; + } + 116 [label="Variable declaration: lval b: R|B|"]; + 117 [label="Access variable R|/b|"]; + 118 [label="Function call: R|/takeB|(...)"]; + 119 [label="Exit block"]; + } + 120 [label="Exit function test_3" style="filled" fillcolor=red]; + } 86 -> {87}; 87 -> {88}; 88 -> {89}; @@ -292,26 +298,32 @@ digraph exhaustiveWhenAndDNNType_kt { 90 -> {91}; 91 -> {92}; 92 -> {93}; - 93 -> {104 94}; + 93 -> {94}; 94 -> {95}; 95 -> {96}; 96 -> {97}; 97 -> {98}; - 98 -> {99}; + 98 -> {110 99}; 99 -> {100}; 100 -> {101}; 101 -> {102}; 102 -> {103}; - 103 -> {109}; + 103 -> {104}; 104 -> {105}; 105 -> {106}; 106 -> {107}; 107 -> {108}; 108 -> {109}; - 109 -> {110}; + 109 -> {115}; 110 -> {111}; 111 -> {112}; 112 -> {113}; 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {119}; + 119 -> {120}; } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.dot index 76f831199d6..62db6ca5fe4 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.dot @@ -234,108 +234,113 @@ digraph when_kt { subgraph cluster_23 { color=blue 83 [label="Enter when branch condition "]; - 84 [label="Type operator: ($subj$ is R|A|)"]; - 85 [label="Exit when branch condition"]; + 84 [label="Exit $subj"]; + 85 [label="Type operator: ($subj$ is R|A|)"]; + 86 [label="Exit when branch condition"]; } subgraph cluster_24 { color=blue - 86 [label="Enter when branch condition "]; - 87 [label="Type operator: ($subj$ is R|B|)"]; - 88 [label="Exit when branch condition"]; + 87 [label="Enter when branch condition "]; + 88 [label="Exit $subj"]; + 89 [label="Type operator: ($subj$ is R|B|)"]; + 90 [label="Exit when branch condition"]; } - 89 [label="Synthetic else branch"]; - 90 [label="Enter when branch result"]; + 91 [label="Synthetic else branch"]; + 92 [label="Enter when branch result"]; subgraph cluster_25 { color=blue - 91 [label="Enter block"]; - 92 [label="Access variable R|/x|"]; - 93 [label="Function call: R|/x|.R|/B.bar|()"]; - 94 [label="Exit block"]; + 93 [label="Enter block"]; + 94 [label="Access variable R|/x|"]; + 95 [label="Function call: R|/x|.R|/B.bar|()"]; + 96 [label="Exit block"]; } - 95 [label="Exit when branch result"]; - 96 [label="Enter when branch result"]; + 97 [label="Exit when branch result"]; + 98 [label="Enter when branch result"]; subgraph cluster_26 { color=blue - 97 [label="Enter block"]; - 98 [label="Access variable R|/x|"]; - 99 [label="Function call: R|/x|.R|/A.foo|()"]; - 100 [label="Exit block"]; + 99 [label="Enter block"]; + 100 [label="Access variable R|/x|"]; + 101 [label="Function call: R|/x|.R|/A.foo|()"]; + 102 [label="Exit block"]; } - 101 [label="Exit when branch result"]; - 102 [label="Exit when"]; + 103 [label="Exit when branch result"]; + 104 [label="Exit when"]; } subgraph cluster_27 { color=blue - 103 [label="Enter when"]; - 104 [label="Access variable R|/x|"]; + 105 [label="Enter when"]; + 106 [label="Access variable R|/x|"]; subgraph cluster_28 { color=blue - 105 [label="Enter when branch condition "]; - 106 [label="Type operator: ($subj$ !is R|A|)"]; - 107 [label="Exit when branch condition"]; + 107 [label="Enter when branch condition "]; + 108 [label="Exit $subj"]; + 109 [label="Type operator: ($subj$ !is R|A|)"]; + 110 [label="Exit when branch condition"]; } subgraph cluster_29 { color=blue - 108 [label="Enter when branch condition "]; - 109 [label="Type operator: ($subj$ !is R|B|)"]; - 110 [label="Exit when branch condition"]; + 111 [label="Enter when branch condition "]; + 112 [label="Exit $subj"]; + 113 [label="Type operator: ($subj$ !is R|B|)"]; + 114 [label="Exit when branch condition"]; } subgraph cluster_30 { color=blue - 111 [label="Enter when branch condition "]; - 112 [label="Type operator: ($subj$ is R|kotlin/Int|)"]; - 113 [label="Exit when branch condition"]; + 115 [label="Enter when branch condition "]; + 116 [label="Exit $subj"]; + 117 [label="Type operator: ($subj$ is R|kotlin/Int|)"]; + 118 [label="Exit when branch condition"]; } subgraph cluster_31 { color=blue - 114 [label="Enter when branch condition else"]; - 115 [label="Exit when branch condition"]; + 119 [label="Enter when branch condition else"]; + 120 [label="Exit when branch condition"]; } - 116 [label="Enter when branch result"]; + 121 [label="Enter when branch result"]; subgraph cluster_32 { color=blue - 117 [label="Enter block"]; - 118 [label="Access variable R|/x|"]; - 119 [label="Function call: R|/x|.R|/A.foo|()"]; - 120 [label="Access variable R|/x|"]; - 121 [label="Function call: R|/x|.R|/B.bar|()"]; - 122 [label="Exit block"]; + 122 [label="Enter block"]; + 123 [label="Access variable R|/x|"]; + 124 [label="Function call: R|/x|.R|/A.foo|()"]; + 125 [label="Access variable R|/x|"]; + 126 [label="Function call: R|/x|.R|/B.bar|()"]; + 127 [label="Exit block"]; } - 123 [label="Exit when branch result"]; - 124 [label="Enter when branch result"]; + 128 [label="Exit when branch result"]; + 129 [label="Enter when branch result"]; subgraph cluster_33 { color=blue - 125 [label="Enter block"]; - 126 [label="Access variable R|/x|"]; - 127 [label="Function call: R|/x|.R|/A.foo|()"]; - 128 [label="Access variable R|/x|"]; - 129 [label="Function call: R|/x|.R|/B.bar|()"]; - 130 [label="Access variable R|/x|"]; - 131 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; - 132 [label="Exit block"]; + 130 [label="Enter block"]; + 131 [label="Access variable R|/x|"]; + 132 [label="Function call: R|/x|.R|/A.foo|()"]; + 133 [label="Access variable R|/x|"]; + 134 [label="Function call: R|/x|.R|/B.bar|()"]; + 135 [label="Access variable R|/x|"]; + 136 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; + 137 [label="Exit block"]; } - 133 [label="Exit when branch result"]; - 134 [label="Enter when branch result"]; + 138 [label="Exit when branch result"]; + 139 [label="Enter when branch result"]; subgraph cluster_34 { color=blue - 135 [label="Enter block"]; - 136 [label="Access variable R|/x|"]; - 137 [label="Function call: R|/x|.R|/A.foo|()"]; - 138 [label="Exit block"]; + 140 [label="Enter block"]; + 141 [label="Access variable R|/x|"]; + 142 [label="Function call: R|/x|.R|/A.foo|()"]; + 143 [label="Exit block"]; } - 139 [label="Exit when branch result"]; - 140 [label="Enter when branch result"]; + 144 [label="Exit when branch result"]; + 145 [label="Enter when branch result"]; subgraph cluster_35 { color=blue - 141 [label="Enter block"]; - 142 [label="Exit block"]; + 146 [label="Enter block"]; + 147 [label="Exit block"]; } - 143 [label="Exit when branch result"]; - 144 [label="Exit when"]; + 148 [label="Exit when branch result"]; + 149 [label="Exit when"]; } - 145 [label="Exit block"]; + 150 [label="Exit block"]; } - 146 [label="Exit function test_2" style="filled" fillcolor=red]; + 151 [label="Exit function test_2" style="filled" fillcolor=red]; } 79 -> {80}; 80 -> {81}; @@ -343,19 +348,19 @@ digraph when_kt { 82 -> {83}; 83 -> {84}; 84 -> {85}; - 85 -> {96 86}; - 86 -> {87}; + 85 -> {86}; + 86 -> {98 87}; 87 -> {88}; - 88 -> {90 89}; - 89 -> {102}; - 90 -> {91}; - 91 -> {92}; + 88 -> {89}; + 89 -> {90}; + 90 -> {92 91}; + 91 -> {104}; 92 -> {93}; 93 -> {94}; 94 -> {95}; - 95 -> {102}; + 95 -> {96}; 96 -> {97}; - 97 -> {98}; + 97 -> {104}; 98 -> {99}; 99 -> {100}; 100 -> {101}; @@ -365,207 +370,212 @@ digraph when_kt { 104 -> {105}; 105 -> {106}; 106 -> {107}; - 107 -> {140 108}; + 107 -> {108}; 108 -> {109}; 109 -> {110}; - 110 -> {134 111}; + 110 -> {145 111}; 111 -> {112}; 112 -> {113}; - 113 -> {124 114}; - 114 -> {115}; + 113 -> {114}; + 114 -> {139 115}; 115 -> {116}; 116 -> {117}; 117 -> {118}; - 118 -> {119}; + 118 -> {129 119}; 119 -> {120}; 120 -> {121}; 121 -> {122}; 122 -> {123}; - 123 -> {144}; + 123 -> {124}; 124 -> {125}; 125 -> {126}; 126 -> {127}; 127 -> {128}; - 128 -> {129}; + 128 -> {149}; 129 -> {130}; 130 -> {131}; 131 -> {132}; 132 -> {133}; - 133 -> {144}; + 133 -> {134}; 134 -> {135}; 135 -> {136}; 136 -> {137}; 137 -> {138}; - 138 -> {139}; - 139 -> {144}; + 138 -> {149}; + 139 -> {140}; 140 -> {141}; 141 -> {142}; 142 -> {143}; 143 -> {144}; - 144 -> {145}; + 144 -> {149}; 145 -> {146}; - - subgraph cluster_36 { - color=red - 147 [label="Enter function test_3" style="filled" fillcolor=red]; - subgraph cluster_37 { - color=blue - 148 [label="Enter block"]; - subgraph cluster_38 { - color=blue - 149 [label="Enter when"]; - 150 [label="Access variable R|/x|"]; - 151 [label="Variable declaration: lval y: R|kotlin/Any?|"]; - subgraph cluster_39 { - color=blue - 152 [label="Enter when branch condition "]; - 153 [label="Type operator: ($subj$ is R|A|)"]; - 154 [label="Exit when branch condition"]; - } - subgraph cluster_40 { - color=blue - 155 [label="Enter when branch condition "]; - 156 [label="Type operator: ($subj$ is R|B|)"]; - 157 [label="Exit when branch condition"]; - } - 158 [label="Synthetic else branch"]; - 159 [label="Enter when branch result"]; - subgraph cluster_41 { - color=blue - 160 [label="Enter block"]; - 161 [label="Access variable R|/x|"]; - 162 [label="Function call: R|/x|.R|/B.bar|()"]; - 163 [label="Access variable R|/y|"]; - 164 [label="Function call: R|/y|.R|/B.bar|()"]; - 165 [label="Exit block"]; - } - 166 [label="Exit when branch result"]; - 167 [label="Enter when branch result"]; - subgraph cluster_42 { - color=blue - 168 [label="Enter block"]; - 169 [label="Access variable R|/x|"]; - 170 [label="Function call: R|/x|.R|/A.foo|()"]; - 171 [label="Access variable R|/y|"]; - 172 [label="Function call: R|/y|.R|/A.foo|()"]; - 173 [label="Exit block"]; - } - 174 [label="Exit when branch result"]; - 175 [label="Exit when"]; - } - subgraph cluster_43 { - color=blue - 176 [label="Enter when"]; - 177 [label="Access variable R|/x|"]; - 178 [label="Variable declaration: lval y: R|kotlin/Any?|"]; - subgraph cluster_44 { - color=blue - 179 [label="Enter when branch condition "]; - 180 [label="Type operator: ($subj$ !is R|A|)"]; - 181 [label="Exit when branch condition"]; - } - subgraph cluster_45 { - color=blue - 182 [label="Enter when branch condition "]; - 183 [label="Type operator: ($subj$ !is R|B|)"]; - 184 [label="Exit when branch condition"]; - } - subgraph cluster_46 { - color=blue - 185 [label="Enter when branch condition "]; - 186 [label="Type operator: ($subj$ is R|kotlin/Int|)"]; - 187 [label="Exit when branch condition"]; - } - subgraph cluster_47 { - color=blue - 188 [label="Enter when branch condition else"]; - 189 [label="Exit when branch condition"]; - } - 190 [label="Enter when branch result"]; - subgraph cluster_48 { - color=blue - 191 [label="Enter block"]; - 192 [label="Access variable R|/x|"]; - 193 [label="Function call: R|/x|.R|/A.foo|()"]; - 194 [label="Access variable R|/x|"]; - 195 [label="Function call: R|/x|.R|/B.bar|()"]; - 196 [label="Access variable R|/y|"]; - 197 [label="Function call: R|/y|.R|/A.foo|()"]; - 198 [label="Access variable R|/y|"]; - 199 [label="Function call: R|/y|.R|/B.bar|()"]; - 200 [label="Exit block"]; - } - 201 [label="Exit when branch result"]; - 202 [label="Enter when branch result"]; - subgraph cluster_49 { - color=blue - 203 [label="Enter block"]; - 204 [label="Access variable R|/x|"]; - 205 [label="Function call: R|/x|.R|/A.foo|()"]; - 206 [label="Access variable R|/x|"]; - 207 [label="Function call: R|/x|.R|/B.bar|()"]; - 208 [label="Access variable R|/x|"]; - 209 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; - 210 [label="Access variable R|/y|"]; - 211 [label="Function call: R|/y|.R|/A.foo|()"]; - 212 [label="Access variable R|/y|"]; - 213 [label="Function call: R|/y|.R|/B.bar|()"]; - 214 [label="Access variable R|/y|"]; - 215 [label="Function call: R|/y|.R|kotlin/Int.inc|()"]; - 216 [label="Exit block"]; - } - 217 [label="Exit when branch result"]; - 218 [label="Enter when branch result"]; - subgraph cluster_50 { - color=blue - 219 [label="Enter block"]; - 220 [label="Access variable R|/x|"]; - 221 [label="Function call: R|/x|.R|/A.foo|()"]; - 222 [label="Access variable R|/y|"]; - 223 [label="Function call: R|/y|.R|/A.foo|()"]; - 224 [label="Exit block"]; - } - 225 [label="Exit when branch result"]; - 226 [label="Enter when branch result"]; - subgraph cluster_51 { - color=blue - 227 [label="Enter block"]; - 228 [label="Exit block"]; - } - 229 [label="Exit when branch result"]; - 230 [label="Exit when"]; - } - 231 [label="Exit block"]; - } - 232 [label="Exit function test_3" style="filled" fillcolor=red]; - } + 146 -> {147}; 147 -> {148}; 148 -> {149}; 149 -> {150}; 150 -> {151}; - 151 -> {152}; + + subgraph cluster_36 { + color=red + 152 [label="Enter function test_3" style="filled" fillcolor=red]; + subgraph cluster_37 { + color=blue + 153 [label="Enter block"]; + subgraph cluster_38 { + color=blue + 154 [label="Enter when"]; + 155 [label="Access variable R|/x|"]; + 156 [label="Variable declaration: lval y: R|kotlin/Any?|"]; + subgraph cluster_39 { + color=blue + 157 [label="Enter when branch condition "]; + 158 [label="Exit $subj"]; + 159 [label="Type operator: ($subj$ is R|A|)"]; + 160 [label="Exit when branch condition"]; + } + subgraph cluster_40 { + color=blue + 161 [label="Enter when branch condition "]; + 162 [label="Exit $subj"]; + 163 [label="Type operator: ($subj$ is R|B|)"]; + 164 [label="Exit when branch condition"]; + } + 165 [label="Synthetic else branch"]; + 166 [label="Enter when branch result"]; + subgraph cluster_41 { + color=blue + 167 [label="Enter block"]; + 168 [label="Access variable R|/x|"]; + 169 [label="Function call: R|/x|.R|/B.bar|()"]; + 170 [label="Access variable R|/y|"]; + 171 [label="Function call: R|/y|.R|/B.bar|()"]; + 172 [label="Exit block"]; + } + 173 [label="Exit when branch result"]; + 174 [label="Enter when branch result"]; + subgraph cluster_42 { + color=blue + 175 [label="Enter block"]; + 176 [label="Access variable R|/x|"]; + 177 [label="Function call: R|/x|.R|/A.foo|()"]; + 178 [label="Access variable R|/y|"]; + 179 [label="Function call: R|/y|.R|/A.foo|()"]; + 180 [label="Exit block"]; + } + 181 [label="Exit when branch result"]; + 182 [label="Exit when"]; + } + subgraph cluster_43 { + color=blue + 183 [label="Enter when"]; + 184 [label="Access variable R|/x|"]; + 185 [label="Variable declaration: lval y: R|kotlin/Any?|"]; + subgraph cluster_44 { + color=blue + 186 [label="Enter when branch condition "]; + 187 [label="Exit $subj"]; + 188 [label="Type operator: ($subj$ !is R|A|)"]; + 189 [label="Exit when branch condition"]; + } + subgraph cluster_45 { + color=blue + 190 [label="Enter when branch condition "]; + 191 [label="Exit $subj"]; + 192 [label="Type operator: ($subj$ !is R|B|)"]; + 193 [label="Exit when branch condition"]; + } + subgraph cluster_46 { + color=blue + 194 [label="Enter when branch condition "]; + 195 [label="Exit $subj"]; + 196 [label="Type operator: ($subj$ is R|kotlin/Int|)"]; + 197 [label="Exit when branch condition"]; + } + subgraph cluster_47 { + color=blue + 198 [label="Enter when branch condition else"]; + 199 [label="Exit when branch condition"]; + } + 200 [label="Enter when branch result"]; + subgraph cluster_48 { + color=blue + 201 [label="Enter block"]; + 202 [label="Access variable R|/x|"]; + 203 [label="Function call: R|/x|.R|/A.foo|()"]; + 204 [label="Access variable R|/x|"]; + 205 [label="Function call: R|/x|.R|/B.bar|()"]; + 206 [label="Access variable R|/y|"]; + 207 [label="Function call: R|/y|.R|/A.foo|()"]; + 208 [label="Access variable R|/y|"]; + 209 [label="Function call: R|/y|.R|/B.bar|()"]; + 210 [label="Exit block"]; + } + 211 [label="Exit when branch result"]; + 212 [label="Enter when branch result"]; + subgraph cluster_49 { + color=blue + 213 [label="Enter block"]; + 214 [label="Access variable R|/x|"]; + 215 [label="Function call: R|/x|.R|/A.foo|()"]; + 216 [label="Access variable R|/x|"]; + 217 [label="Function call: R|/x|.R|/B.bar|()"]; + 218 [label="Access variable R|/x|"]; + 219 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; + 220 [label="Access variable R|/y|"]; + 221 [label="Function call: R|/y|.R|/A.foo|()"]; + 222 [label="Access variable R|/y|"]; + 223 [label="Function call: R|/y|.R|/B.bar|()"]; + 224 [label="Access variable R|/y|"]; + 225 [label="Function call: R|/y|.R|kotlin/Int.inc|()"]; + 226 [label="Exit block"]; + } + 227 [label="Exit when branch result"]; + 228 [label="Enter when branch result"]; + subgraph cluster_50 { + color=blue + 229 [label="Enter block"]; + 230 [label="Access variable R|/x|"]; + 231 [label="Function call: R|/x|.R|/A.foo|()"]; + 232 [label="Access variable R|/y|"]; + 233 [label="Function call: R|/y|.R|/A.foo|()"]; + 234 [label="Exit block"]; + } + 235 [label="Exit when branch result"]; + 236 [label="Enter when branch result"]; + subgraph cluster_51 { + color=blue + 237 [label="Enter block"]; + 238 [label="Exit block"]; + } + 239 [label="Exit when branch result"]; + 240 [label="Exit when"]; + } + 241 [label="Exit block"]; + } + 242 [label="Exit function test_3" style="filled" fillcolor=red]; + } 152 -> {153}; 153 -> {154}; - 154 -> {167 155}; + 154 -> {155}; 155 -> {156}; 156 -> {157}; - 157 -> {159 158}; - 158 -> {175}; + 157 -> {158}; + 158 -> {159}; 159 -> {160}; - 160 -> {161}; + 160 -> {174 161}; 161 -> {162}; 162 -> {163}; 163 -> {164}; - 164 -> {165}; - 165 -> {166}; - 166 -> {175}; + 164 -> {166 165}; + 165 -> {182}; + 166 -> {167}; 167 -> {168}; 168 -> {169}; 169 -> {170}; 170 -> {171}; 171 -> {172}; 172 -> {173}; - 173 -> {174}; + 173 -> {182}; 174 -> {175}; 175 -> {176}; 176 -> {177}; @@ -573,27 +583,27 @@ digraph when_kt { 178 -> {179}; 179 -> {180}; 180 -> {181}; - 181 -> {226 182}; + 181 -> {182}; 182 -> {183}; 183 -> {184}; - 184 -> {218 185}; + 184 -> {185}; 185 -> {186}; 186 -> {187}; - 187 -> {202 188}; + 187 -> {188}; 188 -> {189}; - 189 -> {190}; + 189 -> {236 190}; 190 -> {191}; 191 -> {192}; 192 -> {193}; - 193 -> {194}; + 193 -> {228 194}; 194 -> {195}; 195 -> {196}; 196 -> {197}; - 197 -> {198}; + 197 -> {212 198}; 198 -> {199}; 199 -> {200}; 200 -> {201}; - 201 -> {230}; + 201 -> {202}; 202 -> {203}; 203 -> {204}; 204 -> {205}; @@ -603,13 +613,13 @@ digraph when_kt { 208 -> {209}; 209 -> {210}; 210 -> {211}; - 211 -> {212}; + 211 -> {240}; 212 -> {213}; 213 -> {214}; 214 -> {215}; 215 -> {216}; 216 -> {217}; - 217 -> {230}; + 217 -> {218}; 218 -> {219}; 219 -> {220}; 220 -> {221}; @@ -617,60 +627,61 @@ digraph when_kt { 222 -> {223}; 223 -> {224}; 224 -> {225}; - 225 -> {230}; + 225 -> {226}; 226 -> {227}; - 227 -> {228}; + 227 -> {240}; 228 -> {229}; 229 -> {230}; 230 -> {231}; 231 -> {232}; - - subgraph cluster_52 { - color=red - 233 [label="Enter function test_4" style="filled" fillcolor=red]; - subgraph cluster_53 { - color=blue - 234 [label="Enter block"]; - subgraph cluster_54 { - color=blue - 235 [label="Enter when"]; - 236 [label="Access variable R|/x|"]; - 237 [label="Type operator: (R|/x| as R|kotlin/Int|)"]; - subgraph cluster_55 { - color=blue - 238 [label="Enter when branch condition "]; - 239 [label="Const: Int(1)"]; - 240 [label="Equality operator =="]; - 241 [label="Exit when branch condition"]; - } - 242 [label="Synthetic else branch"]; - 243 [label="Enter when branch result"]; - subgraph cluster_56 { - color=blue - 244 [label="Enter block"]; - 245 [label="Access variable R|/x|"]; - 246 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; - 247 [label="Exit block"]; - } - 248 [label="Exit when branch result"]; - 249 [label="Exit when"]; - } - 250 [label="Access variable R|/x|"]; - 251 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; - 252 [label="Exit block"]; - } - 253 [label="Exit function test_4" style="filled" fillcolor=red]; - } + 232 -> {233}; 233 -> {234}; 234 -> {235}; - 235 -> {236}; + 235 -> {240}; 236 -> {237}; 237 -> {238}; 238 -> {239}; 239 -> {240}; 240 -> {241}; - 241 -> {243 242}; - 242 -> {249}; + 241 -> {242}; + + subgraph cluster_52 { + color=red + 243 [label="Enter function test_4" style="filled" fillcolor=red]; + subgraph cluster_53 { + color=blue + 244 [label="Enter block"]; + subgraph cluster_54 { + color=blue + 245 [label="Enter when"]; + 246 [label="Access variable R|/x|"]; + 247 [label="Type operator: (R|/x| as R|kotlin/Int|)"]; + subgraph cluster_55 { + color=blue + 248 [label="Enter when branch condition "]; + 249 [label="Exit $subj"]; + 250 [label="Const: Int(1)"]; + 251 [label="Equality operator =="]; + 252 [label="Exit when branch condition"]; + } + 253 [label="Synthetic else branch"]; + 254 [label="Enter when branch result"]; + subgraph cluster_56 { + color=blue + 255 [label="Enter block"]; + 256 [label="Access variable R|/x|"]; + 257 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; + 258 [label="Exit block"]; + } + 259 [label="Exit when branch result"]; + 260 [label="Exit when"]; + } + 261 [label="Access variable R|/x|"]; + 262 [label="Function call: R|/x|.R|kotlin/Int.inc|()"]; + 263 [label="Exit block"]; + } + 264 [label="Exit function test_4" style="filled" fillcolor=red]; + } 243 -> {244}; 244 -> {245}; 245 -> {246}; @@ -680,6 +691,17 @@ digraph when_kt { 249 -> {250}; 250 -> {251}; 251 -> {252}; - 252 -> {253}; + 252 -> {254 253}; + 253 -> {260}; + 254 -> {255}; + 255 -> {256}; + 256 -> {257}; + 257 -> {258}; + 258 -> {259}; + 259 -> {260}; + 260 -> {261}; + 261 -> {262}; + 262 -> {263}; + 263 -> {264}; } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.dot new file mode 100644 index 00000000000..cdbb7c68268 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.dot @@ -0,0 +1,198 @@ +digraph whenSubjectExpression_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function whenWithSubjectExpression" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + subgraph cluster_2 { + color=blue + 2 [label="Enter when"]; + 3 [label="Access variable R|/x|"]; + subgraph cluster_3 { + color=blue + 4 [label="Enter when branch condition "]; + 5 [label="Exit $subj"]; + 6 [label="Type operator: ($subj$ !is R|kotlin/Double|)"]; + 7 [label="Exit when branch condition"]; + } + subgraph cluster_4 { + color=blue + 8 [label="Enter when branch condition "]; + 9 [label="Exit $subj"]; + 10 [label="Const: Double(0.0)"]; + 11 [label="Equality operator =="]; + 12 [label="Exit when branch condition"]; + } + subgraph cluster_5 { + color=blue + 13 [label="Enter when branch condition else"]; + 14 [label="Exit when branch condition"]; + } + 15 [label="Enter when branch result"]; + subgraph cluster_6 { + color=blue + 16 [label="Enter block"]; + 17 [label="Access variable R|/x|"]; + 18 [label="Function call: R|/x|.R|kotlin/Double.toInt|()"]; + 19 [label="Exit block"]; + } + 20 [label="Exit when branch result"]; + 21 [label="Enter when branch result"]; + subgraph cluster_7 { + color=blue + 22 [label="Enter block"]; + 23 [label="Const: Int(0)"]; + 24 [label="Exit block"]; + } + 25 [label="Exit when branch result"]; + 26 [label="Enter when branch result"]; + subgraph cluster_8 { + color=blue + 27 [label="Enter block"]; + 28 [label="Const: Int(-1)"]; + 29 [label="Exit block"]; + } + 30 [label="Exit when branch result"]; + 31 [label="Exit when"]; + } + 32 [label="Exit block"]; + } + 33 [label="Exit function whenWithSubjectExpression" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 7 -> {26 8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {21 13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {31}; + 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 cluster_9 { + color=red + 34 [label="Enter function whenWithSubjectVariable" style="filled" fillcolor=red]; + subgraph cluster_10 { + color=blue + 35 [label="Enter block"]; + subgraph cluster_11 { + color=blue + 36 [label="Enter when"]; + 37 [label="Access variable R|/x|"]; + 38 [label="Variable declaration: lval y: R|kotlin/Any|"]; + subgraph cluster_12 { + color=blue + 39 [label="Enter when branch condition "]; + 40 [label="Exit $subj"]; + 41 [label="Type operator: ($subj$ !is R|kotlin/Double|)"]; + 42 [label="Exit when branch condition"]; + } + subgraph cluster_13 { + color=blue + 43 [label="Enter when branch condition "]; + 44 [label="Exit $subj"]; + 45 [label="Const: Double(0.0)"]; + 46 [label="Equality operator =="]; + 47 [label="Exit when branch condition"]; + } + subgraph cluster_14 { + color=blue + 48 [label="Enter when branch condition else"]; + 49 [label="Exit when branch condition"]; + } + 50 [label="Enter when branch result"]; + subgraph cluster_15 { + color=blue + 51 [label="Enter block"]; + 52 [label="Access variable R|/y|"]; + 53 [label="Function call: R|/y|.R|kotlin/Double.toInt|()"]; + 54 [label="Exit block"]; + } + 55 [label="Exit when branch result"]; + 56 [label="Enter when branch result"]; + subgraph cluster_16 { + color=blue + 57 [label="Enter block"]; + 58 [label="Const: Int(0)"]; + 59 [label="Exit block"]; + } + 60 [label="Exit when branch result"]; + 61 [label="Enter when branch result"]; + subgraph cluster_17 { + color=blue + 62 [label="Enter block"]; + 63 [label="Const: Int(-1)"]; + 64 [label="Exit block"]; + } + 65 [label="Exit when branch result"]; + 66 [label="Exit when"]; + } + 67 [label="Exit block"]; + } + 68 [label="Exit function whenWithSubjectVariable" style="filled" fillcolor=red]; + } + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {61 43}; + 43 -> {44}; + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {56 48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {66}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {66}; + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.fir.txt new file mode 100644 index 00000000000..677bfbbb4b6 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.fir.txt @@ -0,0 +1,29 @@ +FILE: whenSubjectExpression.kt + public final fun whenWithSubjectExpression(x: R|kotlin/Any|): R|kotlin/Unit| { + when (R|/x|) { + ($subj$ !is R|kotlin/Double|) -> { + Int(-1) + } + ==($subj$, Double(0.0)) -> { + Int(0) + } + else -> { + R|/x|.R|kotlin/Double.toInt|() + } + } + + } + public final fun whenWithSubjectVariable(x: R|kotlin/Any|): R|kotlin/Unit| { + when (lval y: R|kotlin/Any| = R|/x|) { + ($subj$ !is R|kotlin/Double|) -> { + Int(-1) + } + ==($subj$, Double(0.0)) -> { + Int(0) + } + else -> { + R|/y|.R|kotlin/Double.toInt|() + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt new file mode 100644 index 00000000000..92a39268c69 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt @@ -0,0 +1,18 @@ +// DUMP_CFG +// ISSUE: KT-49860 + +fun whenWithSubjectExpression(x: Any) { + when (x) { + !is Double -> -1 + 0.0 -> 0 // `subj` in `subj == 0.0` must have type 'double' + else -> x.toInt() + } +} + +fun whenWithSubjectVariable(x: Any) { + when (val y = x) { + !is Double -> -1 + 0.0 -> 0 // `subj` in `subj == 0.0` must have type 'double' + else -> y.toInt() + } +} diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot index 2e9ba2f2375..1caf339c387 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.dot @@ -108,88 +108,92 @@ digraph lambdaInWhenBranch_kt { subgraph cluster_14 { color=blue 32 [label="Enter when branch condition "]; - 33 [label="Type operator: ($subj$ is R|SubClass1|)"]; - 34 [label="Exit when branch condition"]; + 33 [label="Exit $subj"]; + 34 [label="Type operator: ($subj$ is R|SubClass1|)"]; + 35 [label="Exit when branch condition"]; } subgraph cluster_15 { color=blue - 35 [label="Enter when branch condition "]; - 36 [label="Type operator: ($subj$ is R|SubClass2|)"]; - 37 [label="Exit when branch condition"]; + 36 [label="Enter when branch condition "]; + 37 [label="Exit $subj"]; + 38 [label="Type operator: ($subj$ is R|SubClass2|)"]; + 39 [label="Exit when branch condition"]; } - 38 [label="Enter when branch result"]; + 40 [label="Enter when branch result"]; subgraph cluster_16 { color=blue - 39 [label="Enter block"]; - 40 [label="Const: String()"]; - 41 [label="Exit block"]; + 41 [label="Enter block"]; + 42 [label="Const: String()"]; + 43 [label="Exit block"]; } - 42 [label="Exit when branch result"]; - 43 [label="Enter when branch result"]; + 44 [label="Exit when branch result"]; + 45 [label="Enter when branch result"]; subgraph cluster_17 { color=blue - 44 [label="Enter block"]; - 45 [label="Const: String()"]; - 46 [label="Postponed enter to lambda"]; + 46 [label="Enter block"]; + 47 [label="Const: String()"]; + 48 [label="Postponed enter to lambda"]; subgraph cluster_18 { color=blue - 77 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 81 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; subgraph cluster_19 { color=blue - 78 [label="Enter block"]; - 79 [label="Access variable R|/it|"]; - 80 [label="Exit block"]; + 82 [label="Enter block"]; + 83 [label="Access variable R|/it|"]; + 84 [label="Exit block"]; } - 81 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 85 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 47 [label="Postponed exit from lambda"]; - 48 [label="Function call: String().R|kotlin/let|(...)"]; - 49 [label="Exit block"]; + 49 [label="Postponed exit from lambda"]; + 50 [label="Function call: String().R|kotlin/let|(...)"]; + 51 [label="Exit block"]; } - 50 [label="Exit when branch result"]; - 51 [label="Exit when"]; + 52 [label="Exit when branch result"]; + 53 [label="Exit when"]; } - 52 [label="Access variable R|/p|"]; - 53 [label="Access variable #"]; + 54 [label="Access variable R|/p|"]; + 55 [label="Access variable #"]; subgraph cluster_20 { color=blue - 54 [label="Enter when"]; - 55 [label="Access variable R|/p|"]; + 56 [label="Enter when"]; + 57 [label="Access variable R|/p|"]; subgraph cluster_21 { color=blue - 56 [label="Enter when branch condition "]; - 57 [label="Type operator: ($subj$ is R|SubClass1|)"]; - 58 [label="Exit when branch condition"]; + 58 [label="Enter when branch condition "]; + 59 [label="Exit $subj"]; + 60 [label="Type operator: ($subj$ is R|SubClass1|)"]; + 61 [label="Exit when branch condition"]; } subgraph cluster_22 { color=blue - 59 [label="Enter when branch condition "]; - 60 [label="Type operator: ($subj$ is R|SubClass2|)"]; - 61 [label="Exit when branch condition"]; + 62 [label="Enter when branch condition "]; + 63 [label="Exit $subj"]; + 64 [label="Type operator: ($subj$ is R|SubClass2|)"]; + 65 [label="Exit when branch condition"]; } - 62 [label="Enter when branch result"]; + 66 [label="Enter when branch result"]; subgraph cluster_23 { color=blue - 63 [label="Enter block"]; - 64 [label="Const: String(2)"]; - 65 [label="Exit block"]; + 67 [label="Enter block"]; + 68 [label="Const: String(2)"]; + 69 [label="Exit block"]; } - 66 [label="Exit when branch result"]; - 67 [label="Enter when branch result"]; + 70 [label="Exit when branch result"]; + 71 [label="Enter when branch result"]; subgraph cluster_24 { color=blue - 68 [label="Enter block"]; - 69 [label="Access variable R|/p|"]; - 70 [label="Access variable R|/SubClass1.t|"]; - 71 [label="Exit block"]; + 72 [label="Enter block"]; + 73 [label="Access variable R|/p|"]; + 74 [label="Access variable R|/SubClass1.t|"]; + 75 [label="Exit block"]; } - 72 [label="Exit when branch result"]; - 73 [label="Exit when"]; + 76 [label="Exit when branch result"]; + 77 [label="Exit when"]; } - 74 [label="Access variable R|kotlin/String.length|"]; - 75 [label="Exit block"]; + 78 [label="Access variable R|kotlin/String.length|"]; + 79 [label="Exit block"]; } - 76 [label="Exit function foo" style="filled" fillcolor=red]; + 80 [label="Exit function foo" style="filled" fillcolor=red]; } 28 -> {29}; 29 -> {30}; @@ -197,23 +201,23 @@ digraph lambdaInWhenBranch_kt { 31 -> {32}; 32 -> {33}; 33 -> {34}; - 34 -> {43 35}; - 35 -> {36}; + 34 -> {35}; + 35 -> {45 36}; 36 -> {37}; 37 -> {38}; 38 -> {39}; 39 -> {40}; 40 -> {41}; 41 -> {42}; - 42 -> {51}; + 42 -> {43}; 43 -> {44}; - 44 -> {45}; + 44 -> {53}; 45 -> {46}; - 46 -> {77}; - 46 -> {47} [color=red]; - 46 -> {77} [style=dashed]; + 46 -> {47}; 47 -> {48}; - 48 -> {49}; + 48 -> {81}; + 48 -> {49} [color=red]; + 48 -> {81} [style=dashed]; 49 -> {50}; 50 -> {51}; 51 -> {52}; @@ -223,28 +227,32 @@ digraph lambdaInWhenBranch_kt { 55 -> {56}; 56 -> {57}; 57 -> {58}; - 58 -> {67 59}; + 58 -> {59}; 59 -> {60}; 60 -> {61}; - 61 -> {62}; + 61 -> {71 62}; 62 -> {63}; 63 -> {64}; 64 -> {65}; 65 -> {66}; - 66 -> {73}; + 66 -> {67}; 67 -> {68}; 68 -> {69}; 69 -> {70}; - 70 -> {71}; + 70 -> {77}; 71 -> {72}; 72 -> {73}; 73 -> {74}; 74 -> {75}; 75 -> {76}; + 76 -> {77}; 77 -> {78}; 78 -> {79}; 79 -> {80}; - 80 -> {81}; - 81 -> {47} [color=green]; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {49} [color=green]; } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceiverAsWhenSubject.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceiverAsWhenSubject.dot index 49dbe7a2b8a..21cf6a48860 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceiverAsWhenSubject.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceiverAsWhenSubject.dot @@ -16,48 +16,50 @@ digraph implicitReceiverAsWhenSubject_kt { subgraph cluster_3 { color=blue 4 [label="Enter when branch condition "]; - 5 [label="Type operator: ($subj$ is R|kotlin/collections/List<*>|)"]; - 6 [label="Exit when branch condition"]; + 5 [label="Exit $subj"]; + 6 [label="Type operator: ($subj$ is R|kotlin/collections/List<*>|)"]; + 7 [label="Exit when branch condition"]; } subgraph cluster_4 { color=blue - 7 [label="Enter when branch condition "]; - 8 [label="Type operator: ($subj$ is R|kotlin/String|)"]; - 9 [label="Exit when branch condition"]; + 8 [label="Enter when branch condition "]; + 9 [label="Exit $subj"]; + 10 [label="Type operator: ($subj$ is R|kotlin/String|)"]; + 11 [label="Exit when branch condition"]; } subgraph cluster_5 { color=blue - 10 [label="Enter when branch condition else"]; - 11 [label="Exit when branch condition"]; + 12 [label="Enter when branch condition else"]; + 13 [label="Exit when branch condition"]; } - 12 [label="Enter when branch result"]; + 14 [label="Enter when branch result"]; subgraph cluster_6 { color=blue - 13 [label="Enter block"]; - 14 [label="Const: Int(0)"]; - 15 [label="Exit block"]; + 15 [label="Enter block"]; + 16 [label="Const: Int(0)"]; + 17 [label="Exit block"]; } - 16 [label="Exit when branch result"]; - 17 [label="Enter when branch result"]; + 18 [label="Exit when branch result"]; + 19 [label="Enter when branch result"]; subgraph cluster_7 { color=blue - 18 [label="Enter block"]; - 19 [label="Access variable R|kotlin/String.length|"]; - 20 [label="Exit block"]; + 20 [label="Enter block"]; + 21 [label="Access variable R|kotlin/String.length|"]; + 22 [label="Exit block"]; } - 21 [label="Exit when branch result"]; - 22 [label="Enter when branch result"]; + 23 [label="Exit when branch result"]; + 24 [label="Enter when branch result"]; subgraph cluster_8 { color=blue - 23 [label="Enter block"]; - 24 [label="Access variable this@R|/test_1|"]; - 25 [label="Access variable R|SubstitutionOverride|"]; - 26 [label="Exit block"]; + 25 [label="Enter block"]; + 26 [label="Access variable this@R|/test_1|"]; + 27 [label="Access variable R|SubstitutionOverride|"]; + 28 [label="Exit block"]; } - 27 [label="Exit when branch result"]; - 28 [label="Exit when"]; + 29 [label="Exit when branch result"]; + 30 [label="Exit when"]; } - 29 [label="Jump: ^test_1 when (this@R|/test_1|) { + 31 [label="Jump: ^test_1 when (this@R|/test_1|) { ($subj$ is R|kotlin/collections/List<*>|) -> { this@R|/test_1|.R|SubstitutionOverride| } @@ -69,10 +71,10 @@ digraph implicitReceiverAsWhenSubject_kt { } } "]; - 30 [label="Stub" style="filled" fillcolor=gray]; - 31 [label="Exit block" style="filled" fillcolor=gray]; + 32 [label="Stub" style="filled" fillcolor=gray]; + 33 [label="Exit block" style="filled" fillcolor=gray]; } - 32 [label="Exit function test_1" style="filled" fillcolor=red]; + 34 [label="Exit function test_1" style="filled" fillcolor=red]; } 0 -> {1}; 1 -> {2}; @@ -80,94 +82,98 @@ digraph implicitReceiverAsWhenSubject_kt { 3 -> {4}; 4 -> {5}; 5 -> {6}; - 6 -> {22 7}; - 7 -> {8}; + 6 -> {7}; + 7 -> {24 8}; 8 -> {9}; - 9 -> {17 10}; + 9 -> {10}; 10 -> {11}; - 11 -> {12}; + 11 -> {19 12}; 12 -> {13}; 13 -> {14}; 14 -> {15}; 15 -> {16}; - 16 -> {28}; + 16 -> {17}; 17 -> {18}; - 18 -> {19}; + 18 -> {30}; 19 -> {20}; 20 -> {21}; - 21 -> {28}; + 21 -> {22}; 22 -> {23}; - 23 -> {24}; + 23 -> {30}; 24 -> {25}; 25 -> {26}; 26 -> {27}; 27 -> {28}; 28 -> {29}; - 29 -> {32}; - 29 -> {30} [style=dotted]; - 30 -> {31} [style=dotted]; + 29 -> {30}; + 30 -> {31}; + 31 -> {34}; 31 -> {32} [style=dotted]; + 32 -> {33} [style=dotted]; + 33 -> {34} [style=dotted]; subgraph cluster_9 { color=red - 33 [label="Enter function test_2" style="filled" fillcolor=red]; + 35 [label="Enter function test_2" style="filled" fillcolor=red]; subgraph cluster_10 { color=blue - 34 [label="Enter block"]; + 36 [label="Enter block"]; subgraph cluster_11 { color=blue - 35 [label="Enter when"]; - 36 [label="Access variable this@R|/test_2|"]; - 37 [label="Variable declaration: lval x: R|kotlin/Any|"]; + 37 [label="Enter when"]; + 38 [label="Access variable this@R|/test_2|"]; + 39 [label="Variable declaration: lval x: R|kotlin/Any|"]; subgraph cluster_12 { color=blue - 38 [label="Enter when branch condition "]; - 39 [label="Type operator: ($subj$ is R|kotlin/collections/List<*>|)"]; - 40 [label="Exit when branch condition"]; + 40 [label="Enter when branch condition "]; + 41 [label="Exit $subj"]; + 42 [label="Type operator: ($subj$ is R|kotlin/collections/List<*>|)"]; + 43 [label="Exit when branch condition"]; } subgraph cluster_13 { color=blue - 41 [label="Enter when branch condition "]; - 42 [label="Type operator: ($subj$ is R|kotlin/String|)"]; - 43 [label="Exit when branch condition"]; + 44 [label="Enter when branch condition "]; + 45 [label="Exit $subj"]; + 46 [label="Type operator: ($subj$ is R|kotlin/String|)"]; + 47 [label="Exit when branch condition"]; } subgraph cluster_14 { color=blue - 44 [label="Enter when branch condition else"]; - 45 [label="Exit when branch condition"]; + 48 [label="Enter when branch condition else"]; + 49 [label="Exit when branch condition"]; } - 46 [label="Enter when branch result"]; + 50 [label="Enter when branch result"]; subgraph cluster_15 { color=blue - 47 [label="Enter block"]; - 48 [label="Const: Int(0)"]; - 49 [label="Exit block"]; + 51 [label="Enter block"]; + 52 [label="Const: Int(0)"]; + 53 [label="Exit block"]; } - 50 [label="Exit when branch result"]; - 51 [label="Enter when branch result"]; + 54 [label="Exit when branch result"]; + 55 [label="Enter when branch result"]; subgraph cluster_16 { color=blue - 52 [label="Enter block"]; - 53 [label="Access variable R|/x|"]; - 54 [label="Access variable R|kotlin/String.length|"]; - 55 [label="Access variable R|kotlin/String.length|"]; - 56 [label="Exit block"]; + 56 [label="Enter block"]; + 57 [label="Access variable R|/x|"]; + 58 [label="Access variable R|kotlin/String.length|"]; + 59 [label="Access variable R|kotlin/String.length|"]; + 60 [label="Exit block"]; } - 57 [label="Exit when branch result"]; - 58 [label="Enter when branch result"]; + 61 [label="Exit when branch result"]; + 62 [label="Enter when branch result"]; subgraph cluster_17 { color=blue - 59 [label="Enter block"]; - 60 [label="Access variable R|/x|"]; - 61 [label="Access variable R|SubstitutionOverride|"]; - 62 [label="Access variable this@R|/test_2|"]; - 63 [label="Access variable R|SubstitutionOverride|"]; - 64 [label="Exit block"]; + 63 [label="Enter block"]; + 64 [label="Access variable R|/x|"]; + 65 [label="Access variable R|SubstitutionOverride|"]; + 66 [label="Access variable this@R|/test_2|"]; + 67 [label="Access variable R|SubstitutionOverride|"]; + 68 [label="Exit block"]; } - 65 [label="Exit when branch result"]; - 66 [label="Exit when"]; + 69 [label="Exit when branch result"]; + 70 [label="Exit when"]; } - 67 [label="Jump: ^test_2 when (lval x: R|kotlin/Any| = this@R|/test_2|) { + 71 [label="Jump: ^test_2 when (lval x: R|kotlin/Any| = this@R|/test_2|) { ($subj$ is R|kotlin/collections/List<*>|) -> { R|/x|.R|SubstitutionOverride| this@R|/test_2|.R|SubstitutionOverride| @@ -181,48 +187,50 @@ digraph implicitReceiverAsWhenSubject_kt { } } "]; - 68 [label="Stub" style="filled" fillcolor=gray]; - 69 [label="Exit block" style="filled" fillcolor=gray]; + 72 [label="Stub" style="filled" fillcolor=gray]; + 73 [label="Exit block" style="filled" fillcolor=gray]; } - 70 [label="Exit function test_2" style="filled" fillcolor=red]; + 74 [label="Exit function test_2" style="filled" fillcolor=red]; } - 33 -> {34}; - 34 -> {35}; 35 -> {36}; 36 -> {37}; 37 -> {38}; 38 -> {39}; 39 -> {40}; - 40 -> {58 41}; + 40 -> {41}; 41 -> {42}; 42 -> {43}; - 43 -> {51 44}; + 43 -> {62 44}; 44 -> {45}; 45 -> {46}; 46 -> {47}; - 47 -> {48}; + 47 -> {55 48}; 48 -> {49}; 49 -> {50}; - 50 -> {66}; + 50 -> {51}; 51 -> {52}; 52 -> {53}; 53 -> {54}; - 54 -> {55}; + 54 -> {70}; 55 -> {56}; 56 -> {57}; - 57 -> {66}; + 57 -> {58}; 58 -> {59}; 59 -> {60}; 60 -> {61}; - 61 -> {62}; + 61 -> {70}; 62 -> {63}; 63 -> {64}; 64 -> {65}; 65 -> {66}; 66 -> {67}; - 67 -> {70}; - 67 -> {68} [style=dotted]; - 68 -> {69} [style=dotted]; - 69 -> {70} [style=dotted]; + 67 -> {68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {74}; + 71 -> {72} [style=dotted]; + 72 -> {73} [style=dotted]; + 73 -> {74} [style=dotted]; } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 6cade97e2d7..0fcb1434f6a 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -3657,6 +3657,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { public void testWhen() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.kt"); } + + @Test + @TestMetadata("whenSubjectExpression.kt") + public void testWhenSubjectExpression() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 225cfa0e674..d0a7bf1ce69 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -3657,6 +3657,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos public void testWhen() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/when.kt"); } + + @Test + @TestMetadata("whenSubjectExpression.kt") + public void testWhenSubjectExpression() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures/whenSubjectExpression.kt"); + } } @Nested diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt index d407dc85362..e56220e6a33 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt @@ -290,6 +290,25 @@ class Fir2IrImplicitCastInserter( return data } + override fun visitWhenSubjectExpressionWithSmartcast( + whenSubjectExpressionWithSmartcast: FirWhenSubjectExpressionWithSmartcast, + data: IrElement + ): IrElement { + return if (whenSubjectExpressionWithSmartcast.isStable) { + implicitCastOrExpression(data as IrExpression, whenSubjectExpressionWithSmartcast.typeRef) + } else { + data as IrExpression + } + } + + override fun visitWhenSubjectExpressionWithSmartcastToNull( + whenSubjectExpressionWithSmartcastToNull: FirWhenSubjectExpressionWithSmartcastToNull, + data: IrElement + ): IrElement { + // We don't want an implicit cast to Nothing?. This expression just encompasses nullability after null check. + return data + } + internal fun implicitCastFromDispatchReceiver( original: IrExpression, originalTypeRef: FirTypeRef, diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index c3388af3b79..7f4ce5426d6 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -478,6 +478,22 @@ class Fir2IrVisitor( return convertToIrExpression(expressionWithSmartcastToNull.originalExpression) } + override fun visitWhenSubjectExpressionWithSmartcast( + whenSubjectExpressionWithSmartcast: FirWhenSubjectExpressionWithSmartcast, + data: Any? + ): IrElement { + val value = visitWhenSubjectExpression(whenSubjectExpressionWithSmartcast.originalExpression, data) + return implicitCastInserter.visitWhenSubjectExpressionWithSmartcast(whenSubjectExpressionWithSmartcast, value) + } + + override fun visitWhenSubjectExpressionWithSmartcastToNull( + whenSubjectExpressionWithSmartcastToNull: FirWhenSubjectExpressionWithSmartcastToNull, + data: Any? + ): IrElement { + // This should not be materialized. Generate the expression with the original expression. + return visitWhenSubjectExpression(whenSubjectExpressionWithSmartcastToNull.originalExpression, data) + } + override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { val explicitReceiverExpression = convertToIrReceiverExpression( callableReferenceAccess.explicitReceiver, callableReferenceAccess.calleeReference, callableReferenceAccess diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index dcfbd74609b..42d884fc6bd 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.canNarrowDownGetterType import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType import org.jetbrains.kotlin.fir.declarations.utils.isFinal -import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic @@ -31,6 +30,8 @@ import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue +import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer +import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType @@ -291,26 +292,52 @@ private fun BodyResolveComponents.typeFromSymbol(symbol: FirBasedSymbol<*>, make fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( qualifiedAccessExpression: FirQualifiedAccessExpression ): FirQualifiedAccessExpression { - val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression) - ?: return qualifiedAccessExpression + val builder = transformExpressionUsingSmartcastInfo( + qualifiedAccessExpression, + dataFlowAnalyzer::getTypeUsingSmartcastInfo, + ::FirExpressionWithSmartcastBuilder, + ::FirExpressionWithSmartcastToNullBuilder + ) ?: return qualifiedAccessExpression + return builder.build() +} + +fun BodyResolveComponents.transformWhenSubjectExpressionUsingSmartcastInfo( + whenSubjectExpression: FirWhenSubjectExpression +): FirWhenSubjectExpression { + val builder = transformExpressionUsingSmartcastInfo( + whenSubjectExpression, + dataFlowAnalyzer::getTypeUsingSmartcastInfo, + ::FirWhenSubjectExpressionWithSmartcastBuilder, + ::FirWhenSubjectExpressionWithSmartcastToNullBuilder + ) ?: return whenSubjectExpression + return builder.build() +} + +private inline fun BodyResolveComponents.transformExpressionUsingSmartcastInfo( + expression: T, + smartcastExtractor: (T) -> Pair>?, + smartcastBuilder: () -> FirWrappedExpressionWithSmartcastBuilder, + smartcastToNullBuilder: () -> FirWrappedExpressionWithSmartcastToNullBuilder +): FirWrappedExpressionWithSmartcastBuilder? { + val (stability, typesFromSmartCast) = smartcastExtractor(expression) ?: return null val smartcastStability = stability.impliedSmartcastStability - ?: if (dataFlowAnalyzer.isAccessToUnstableLocalVariable(qualifiedAccessExpression)) { + ?: if (dataFlowAnalyzer.isAccessToUnstableLocalVariable(expression)) { SmartcastStability.CAPTURED_VARIABLE } else { SmartcastStability.STABLE_VALUE } - val originalType = qualifiedAccessExpression.resultType.coneType + val originalType = expression.resultType.coneType val allTypes = typesFromSmartCast.also { it += originalType } val intersectedType = ConeTypeIntersector.intersectTypes(session.typeContext, allTypes) - if (intersectedType == originalType) return qualifiedAccessExpression + if (intersectedType == originalType) return null val intersectedTypeRef = buildResolvedTypeRef { - source = qualifiedAccessExpression.resultType.source?.fakeElement(KtFakeSourceElementKind.SmartCastedTypeRef) + source = expression.resultType.source?.fakeElement(KtFakeSourceElementKind.SmartCastedTypeRef) type = intersectedType - annotations += qualifiedAccessExpression.resultType.annotations - delegatedTypeRef = qualifiedAccessExpression.resultType + annotations += expression.resultType.annotations + delegatedTypeRef = expression.resultType } // For example, if (x == null) { ... }, // we need to track the type without `Nothing?` so that resolution with this as receiver can go through properly. @@ -322,13 +349,13 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( val intersectedTypeWithoutNullableNothing = ConeTypeIntersector.intersectTypes(session.typeContext, typesFromSmartcastWithoutNullableNothing) val intersectedTypeRefWithoutNullableNothing = buildResolvedTypeRef { - source = qualifiedAccessExpression.resultType.source?.fakeElement(KtFakeSourceElementKind.SmartCastedTypeRef) + source = expression.resultType.source?.fakeElement(KtFakeSourceElementKind.SmartCastedTypeRef) type = intersectedTypeWithoutNullableNothing - annotations += qualifiedAccessExpression.resultType.annotations - delegatedTypeRef = qualifiedAccessExpression.resultType + annotations += expression.resultType.annotations + delegatedTypeRef = expression.resultType } - return buildExpressionWithSmartcastToNull { - originalExpression = qualifiedAccessExpression + return smartcastToNullBuilder().apply { + originalExpression = expression smartcastType = intersectedTypeRef smartcastTypeWithoutNullableNothing = intersectedTypeRefWithoutNullableNothing this.typesFromSmartCast = typesFromSmartCast @@ -336,8 +363,8 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( } } - return buildExpressionWithSmartcast { - originalExpression = qualifiedAccessExpression + return smartcastBuilder().apply { + originalExpression = expression smartcastType = intersectedTypeRef this.typesFromSmartCast = typesFromSmartCast this.smartcastStability = smartcastStability diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index bfd7c4815dc..0257b99f08f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -6,8 +6,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.PrivateForInline +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription import org.jetbrains.kotlin.fir.contracts.description.ConeBooleanConstantReference import org.jetbrains.kotlin.fir.contracts.description.ConeConditionalEffectDeclaration @@ -17,7 +16,6 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack @@ -35,7 +33,6 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.visibilityChecker import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.types.ConstantValueKind @@ -165,18 +162,41 @@ abstract class FirDataFlowAnalyzer( // ----------------------------------- Requests ----------------------------------- - fun isAccessToUnstableLocalVariable(qualifiedAccessExpression: FirQualifiedAccessExpression): Boolean { + fun isAccessToUnstableLocalVariable(expression: FirExpression): Boolean { + val qualifiedAccessExpression = when (expression) { + is FirQualifiedAccessExpression -> expression + is FirWhenSubjectExpression -> { + val whenExpression = expression.whenRef.value + when { + whenExpression.subjectVariable != null -> return true + else -> whenExpression.subject as? FirQualifiedAccessExpression + } + } + else -> null + } ?: return false return context.firLocalVariableAssignmentAnalyzer?.isAccessToUnstableLocalVariable(qualifiedAccessExpression) == true } + fun getTypeUsingSmartcastInfo(whenSubjectExpression: FirWhenSubjectExpression): Pair>? { + val symbol = whenSubjectExpression.symbol ?: return null + return getTypeUsingSmartcastInfo(symbol, whenSubjectExpression) + } + fun getTypeUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): Pair>? { /* * DataFlowAnalyzer holds variables only for declarations that have some smartcast (or can have) * If there is no useful information there is no data flow variable also */ val symbol: FirBasedSymbol<*> = qualifiedAccessExpression.symbol ?: return null + return getTypeUsingSmartcastInfo(symbol, qualifiedAccessExpression) + } + + private fun getTypeUsingSmartcastInfo( + symbol: FirBasedSymbol<*>, + expression: FirExpression + ): Pair>? { val flow = graphBuilder.lastNode.flow - var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(symbol, qualifiedAccessExpression, flow) ?: return null + var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(symbol, expression, flow) ?: return null val stability = variable.stability val result = mutableListOf() flow.directAliasMap[variable]?.let { @@ -740,6 +760,10 @@ abstract class FirDataFlowAnalyzer( whenExitNode.mergeIncomingFlow() } + fun exitWhenSubjectExpression(expression: FirWhenSubjectExpression) { + graphBuilder.exitWhenSubjectExpression(expression).mergeIncomingFlow() + } + // ----------------------------------- While Loop ----------------------------------- private fun exitCommonLoop(exitNode: LoopExitNode) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index b02d248d65d..6dd36e61246 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -1178,6 +1178,9 @@ class ControlFlowGraphBuilder { return Pair(kind, unionNode) } + fun exitWhenSubjectExpression(expression: FirWhenSubjectExpression): WhenSubjectExpressionExitNode { + return createWhenSubjectExpressionExitNode(expression).also { addNewSimpleNode(it) } + } // ----------------------------------- Annotations ----------------------------------- diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt index 0e39fc41e4c..6cc15f067a1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt @@ -157,6 +157,9 @@ fun ControlFlowGraphBuilder.createElvisRhsEnterNode(fir: FirElvisExpression): El fun ControlFlowGraphBuilder.createElvisLhsExitNode(fir: FirElvisExpression): ElvisLhsExitNode = ElvisLhsExitNode(currentGraph, fir, levelCounter, createId()) +fun ControlFlowGraphBuilder.createWhenSubjectExpressionExitNode(fir: FirWhenSubjectExpression): WhenSubjectExpressionExitNode = + WhenSubjectExpressionExitNode(currentGraph, fir, levelCounter, createId()) + fun ControlFlowGraphBuilder.createElvisExitNode(fir: FirElvisExpression): ElvisExitNode = ElvisExitNode(currentGraph, fir, levelCounter, createId()) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt index b776737b613..9c831996154 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.isUnitOrFlexibleUnit +import org.jetbrains.kotlin.fir.resolve.transformWhenSubjectExpressionUsingSmartcastInfo import org.jetbrains.kotlin.fir.resolve.transformers.FirSyntheticCallGenerator import org.jetbrains.kotlin.fir.resolve.transformers.FirWhenExhaustivenessTransformer import org.jetbrains.kotlin.fir.resolve.withExpectedType @@ -126,7 +127,8 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran if (subjectType != null) { whenSubjectExpression.resultType = subjectType } - return whenSubjectExpression + dataFlowAnalyzer.exitWhenSubjectExpression(whenSubjectExpression) + return components.transformWhenSubjectExpressionUsingSmartcastInfo(whenSubjectExpression) } // ------------------------------- Try/catch expressions ------------------------------- diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt index 9ab4691bda2..8965e53d9c3 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt @@ -794,6 +794,12 @@ class ElvisExitNode(owner: ControlFlowGraph, override val fir: FirElvisExpressio } } +class WhenSubjectExpressionExitNode(owner: ControlFlowGraph, override val fir: FirWhenSubjectExpression, level: Int, id: Int) : CFGNode(owner, level, id) { + override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { + return visitor.visitWhenSubjectExpressionExitNode(this, data) + } +} + // ----------------------------------- Other ----------------------------------- @OptIn(CfgInternals::class) diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt index 699178cbe49..504c155fd2f 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt @@ -99,6 +99,8 @@ fun CFGNode<*>.render(): String = is EnterSafeCallNode -> "Enter safe call" is ExitSafeCallNode -> "Exit safe call" + is WhenSubjectExpressionExitNode -> "Exit ${'$'}subj" + is PostponedLambdaEnterNode -> "Postponed enter to lambda" is PostponedLambdaExitNode -> "Postponed exit from lambda" diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt index 34497d3648c..0ccfe858b77 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt @@ -347,6 +347,10 @@ abstract class ControlFlowGraphVisitor { return visitNode(node, data) } + open fun visitWhenSubjectExpressionExitNode(node: WhenSubjectExpressionExitNode, data: D): R { + return visitNode(node, data) + } + // ----------------------------------- Elvis ----------------------------------- open fun visitElvisLhsExitNode(node: ElvisLhsExitNode, data: D): R { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastBuilder.kt index 2be61ea3fc2..ae9c205df18 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastBuilder.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastBuilder.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionWithSmartcastImpl class FirExpressionWithSmartcastBuilder : FirWrappedExpressionWithSmartcastBuilder() { - fun build(): FirExpressionWithSmartcast { + override fun build(): FirExpressionWithSmartcast { return FirExpressionWithSmartcastImpl(originalExpression, smartcastType, typesFromSmartCast, smartcastStability) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt index d944698331a..7e56657fb4c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionWithSmartcastToNullImpl class FirExpressionWithSmartcastToNullBuilder : FirWrappedExpressionWithSmartcastToNullBuilder() { - fun build(): FirExpressionWithSmartcastToNull { + override fun build(): FirExpressionWithSmartcastToNull { return FirExpressionWithSmartcastToNullImpl( originalExpression, smartcastType, diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastBuilder.kt index 1032541e2f2..eb1b09109dd 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastBuilder.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastBuilder.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhenSubjectExpressionWithSmartcas import org.jetbrains.kotlin.fir.expressions.impl.FirWhenSubjectExpressionWithSmartcastImpl class FirWhenSubjectExpressionWithSmartcastBuilder : FirWrappedExpressionWithSmartcastBuilder() { - fun build(): FirWhenSubjectExpressionWithSmartcast { + override fun build(): FirWhenSubjectExpressionWithSmartcast { return FirWhenSubjectExpressionWithSmartcastImpl(originalExpression, smartcastType, typesFromSmartCast, smartcastStability) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastToNullBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastToNullBuilder.kt index 6ca47e2244c..953de742174 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastToNullBuilder.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWhenSubjectExpressionWithSmartcastToNullBuilder.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhenSubjectExpressionWithSmartcas import org.jetbrains.kotlin.fir.expressions.impl.FirWhenSubjectExpressionWithSmartcastToNullImpl class FirWhenSubjectExpressionWithSmartcastToNullBuilder : FirWrappedExpressionWithSmartcastToNullBuilder() { - fun build(): FirWhenSubjectExpressionWithSmartcastToNull { + override fun build(): FirWhenSubjectExpressionWithSmartcastToNull { return FirWhenSubjectExpressionWithSmartcastToNullImpl( originalExpression, smartcastType, diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWrappedExpressionWithSmartcastBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWrappedExpressionWithSmartcastBuilder.kt index bae17482087..3babf5a55b5 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWrappedExpressionWithSmartcastBuilder.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirWrappedExpressionWithSmartcastBuilder.kt @@ -15,6 +15,8 @@ abstract class FirWrappedExpressionWithSmartcastBuilder { lateinit var smartcastType: FirTypeRef lateinit var typesFromSmartCast: Collection lateinit var smartcastStability: SmartcastStability + + abstract fun build(): E } abstract class FirWrappedExpressionWithSmartcastToNullBuilder : FirWrappedExpressionWithSmartcastBuilder() { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastImpl.kt index 199e54d8745..728275f95f5 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastImpl.kt @@ -44,7 +44,8 @@ class FirWhenSubjectExpressionWithSmartcastImpl( originalExpression.accept(visitor, data) } - override fun transformChildren(transformer: FirTransformer, data: D): FirElement { - throw IllegalStateException() + override fun transformChildren(transformer: FirTransformer, data: D): FirWhenSubjectExpressionWithSmartcastImpl { + originalExpression = originalExpression.transform(transformer, data) + return this } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastToNullImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastToNullImpl.kt index 3a54e8aeca2..487da327ac4 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastToNullImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionWithSmartcastToNullImpl.kt @@ -45,7 +45,8 @@ class FirWhenSubjectExpressionWithSmartcastToNullImpl( originalExpression.accept(visitor, data) } - override fun transformChildren(transformer: FirTransformer, data: D): FirElement { - throw IllegalStateException() + override fun transformChildren(transformer: FirTransformer, data: D): FirWhenSubjectExpressionWithSmartcastToNullImpl { + originalExpression = originalExpression.transform(transformer, data) + return this } } diff --git a/compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranch_properIeeeComparisons.kt b/compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranch_properIeeeComparisons.kt index 8cc4e768272..69aa160c940 100644 --- a/compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranch_properIeeeComparisons.kt +++ b/compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranch_properIeeeComparisons.kt @@ -1,6 +1,4 @@ // !LANGUAGE: +ProperIeee754Comparisons -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: Fail 1: other fun testF(x: Any) = when (x) { @@ -24,4 +22,4 @@ fun box(): String { if (td != "0.0") return "Fail 2: $td" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/smartCasts/kt44814.dot b/compiler/testData/codegen/box/smartCasts/kt44814.dot index 3425f9620c6..31342401814 100644 --- a/compiler/testData/codegen/box/smartCasts/kt44814.dot +++ b/compiler/testData/codegen/box/smartCasts/kt44814.dot @@ -468,7 +468,7 @@ digraph kt44814_kt { } 141 -> {142}; 142 -> {143}; - 143 -> {282} [color=green]; + 143 -> {285} [color=green]; subgraph cluster_47 { color=red @@ -566,103 +566,106 @@ digraph kt44814_kt { subgraph cluster_58 { color=blue 173 [label="Enter when branch condition [4]"]; - 174 [label="Const: Null(null) [5]"]; - 175 [label="Equality operator == [5]"]; - 176 [label="Exit when branch condition [4]"]; + 174 [label="Exit $subj [5]"]; + 175 [label="Const: Null(null) [5]"]; + 176 [label="Equality operator == [5]"]; + 177 [label="Exit when branch condition [4]"]; } subgraph cluster_59 { color=blue - 177 [label="Enter when branch condition [5]"]; - 178 [label="Type operator: ($subj$ is R|FirPsiSourceElement|) [6]"]; - 179 [label="Exit when branch condition [5]"]; + 178 [label="Enter when branch condition [5]"]; + 179 [label="Exit $subj [6]"]; + 180 [label="Type operator: ($subj$ is R|FirPsiSourceElement|) [6]"]; + 181 [label="Exit when branch condition [5]"]; } subgraph cluster_60 { color=blue - 180 [label="Enter when branch condition [6]"]; - 181 [label="Type operator: ($subj$ is R|FirLightSourceElement|) [7]"]; - 182 [label="Exit when branch condition [6]"]; + 182 [label="Enter when branch condition [6]"]; + 183 [label="Exit $subj [7]"]; + 184 [label="Type operator: ($subj$ is R|FirLightSourceElement|) [7]"]; + 185 [label="Exit when branch condition [6]"]; } - 183 [label="Enter when branch result [7]"]; + 186 [label="Enter when branch result [7]"]; subgraph cluster_61 { color=blue - 184 [label="Enter block [7]"]; - 185 [label="Access variable R|/FirLightSourceElement.lighterASTNode| [9]"]; - 186 [label="Access variable R|/FirLightSourceElement.treeStructure| [9]"]; - 187 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...) [8]"]; - 188 [label="Postponed enter to lambda [8]"]; + 187 [label="Enter block [7]"]; + 188 [label="Access variable R|/FirLightSourceElement.lighterASTNode| [9]"]; + 189 [label="Access variable R|/FirLightSourceElement.treeStructure| [9]"]; + 190 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...) [8]"]; + 191 [label="Postponed enter to lambda [8]"]; subgraph cluster_62 { color=blue - 234 [label="Enter function anonymousFunction [9]" style="filled" fillcolor=red]; + 237 [label="Enter function anonymousFunction [9]" style="filled" fillcolor=red]; subgraph cluster_63 { color=blue - 235 [label="Enter block [9]"]; - 236 [label="Access variable R|/it| [9]"]; - 237 [label="Enter safe call [9]"]; - 238 [label="Access variable R|/LighterASTNode.tokenType| [9]"]; - 239 [label="Exit safe call [9]"]; - 240 [label="Access qualifier /TokenType [9]"]; - 241 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [9]"]; - 242 [label="Equality operator == [9]"]; - 243 [label="Exit block [9]"]; + 238 [label="Enter block [9]"]; + 239 [label="Access variable R|/it| [9]"]; + 240 [label="Enter safe call [9]"]; + 241 [label="Access variable R|/LighterASTNode.tokenType| [9]"]; + 242 [label="Exit safe call [9]"]; + 243 [label="Access qualifier /TokenType [9]"]; + 244 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [9]"]; + 245 [label="Equality operator == [9]"]; + 246 [label="Exit block [9]"]; } - 244 [label="Exit function anonymousFunction [9]" style="filled" fillcolor=red]; + 247 [label="Exit function anonymousFunction [9]" style="filled" fillcolor=red]; } - 189 [label="Postponed exit from lambda [8]"]; - 190 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|(...) [7]"]; - 191 [label="Exit lhs of ?: [7]"]; - 192 [label="Enter rhs of ?: [7]"]; - 193 [label="Const: Null(null) [7]"]; - 194 [label="Jump: ^getModifierList Null(null) [7]"]; - 195 [label="Stub [7]" style="filled" fillcolor=gray]; - 196 [label="Lhs of ?: is not null [7]"]; - 197 [label="Exit ?: [7]"]; - 198 [label="Variable declaration: lval modifierListNode: R|LighterASTNode| [7]"]; - 199 [label="Access variable R|/modifierListNode| [8]"]; - 200 [label="Access variable R|/FirLightSourceElement.treeStructure| [8]"]; - 201 [label="Function call: R|/FirModifierList.FirLightModifierList.FirLightModifierList|(...) [7]"]; - 202 [label="Exit block [7]"]; + 192 [label="Postponed exit from lambda [8]"]; + 193 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|(...) [7]"]; + 194 [label="Exit lhs of ?: [7]"]; + 195 [label="Enter rhs of ?: [7]"]; + 196 [label="Const: Null(null) [7]"]; + 197 [label="Jump: ^getModifierList Null(null) [7]"]; + 198 [label="Stub [7]" style="filled" fillcolor=gray]; + 199 [label="Lhs of ?: is not null [7]"]; + 200 [label="Exit ?: [7]"]; + 201 [label="Variable declaration: lval modifierListNode: R|LighterASTNode| [7]"]; + 202 [label="Access variable R|/modifierListNode| [8]"]; + 203 [label="Access variable R|/FirLightSourceElement.treeStructure| [8]"]; + 204 [label="Function call: R|/FirModifierList.FirLightModifierList.FirLightModifierList|(...) [7]"]; + 205 [label="Exit block [7]"]; } - 203 [label="Exit when branch result [6]"]; - 204 [label="Enter when branch result [6]"]; + 206 [label="Exit when branch result [6]"]; + 207 [label="Enter when branch result [6]"]; subgraph cluster_64 { color=blue - 205 [label="Enter block [6]"]; - 206 [label="Access variable R|/FirPsiSourceElement.psi| [6]"]; - 207 [label="Type operator: (this@R|/FirModifierList.Companion.getModifierList|.R|/FirPsiSourceElement.psi| as? R|KtModifierListOwner|) [6]"]; - 208 [label="Enter safe call [6]"]; - 209 [label="Access variable R|/KtModifierListOwner.modifierList| [6]"]; - 210 [label="Exit safe call [6]"]; + 208 [label="Enter block [6]"]; + 209 [label="Access variable R|/FirPsiSourceElement.psi| [6]"]; + 210 [label="Type operator: (this@R|/FirModifierList.Companion.getModifierList|.R|/FirPsiSourceElement.psi| as? R|KtModifierListOwner|) [6]"]; 211 [label="Enter safe call [6]"]; - 212 [label="Postponed enter to lambda [7]"]; + 212 [label="Access variable R|/KtModifierListOwner.modifierList| [6]"]; + 213 [label="Exit safe call [6]"]; + 214 [label="Enter safe call [6]"]; + 215 [label="Postponed enter to lambda [7]"]; subgraph cluster_65 { color=blue - 228 [label="Enter function anonymousFunction [8]" style="filled" fillcolor=red]; + 231 [label="Enter function anonymousFunction [8]" style="filled" fillcolor=red]; subgraph cluster_66 { color=blue - 229 [label="Enter block [8]"]; - 230 [label="Access variable R|/it| [9]"]; - 231 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [8]"]; - 232 [label="Exit block [8]"]; + 232 [label="Enter block [8]"]; + 233 [label="Access variable R|/it| [9]"]; + 234 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [8]"]; + 235 [label="Exit block [8]"]; } - 233 [label="Exit function anonymousFunction [8]" style="filled" fillcolor=red]; + 236 [label="Exit function anonymousFunction [8]" style="filled" fillcolor=red]; } - 213 [label="Postponed exit from lambda [7]"]; - 214 [label="Function call: $subj$.R|kotlin/let|(...) [6]"]; - 215 [label="Exit safe call [6]"]; - 216 [label="Exit block [6]"]; + 216 [label="Postponed exit from lambda [7]"]; + 217 [label="Function call: $subj$.R|kotlin/let|(...) [6]"]; + 218 [label="Exit safe call [6]"]; + 219 [label="Exit block [6]"]; } - 217 [label="Exit when branch result [5]"]; - 218 [label="Enter when branch result [5]"]; + 220 [label="Exit when branch result [5]"]; + 221 [label="Enter when branch result [5]"]; subgraph cluster_67 { color=blue - 219 [label="Enter block [5]"]; - 220 [label="Const: Null(null) [5]"]; - 221 [label="Exit block [5]"]; + 222 [label="Enter block [5]"]; + 223 [label="Const: Null(null) [5]"]; + 224 [label="Exit block [5]"]; } - 222 [label="Exit when branch result [4]"]; - 223 [label="Exit when [3]"]; + 225 [label="Exit when branch result [4]"]; + 226 [label="Exit when [3]"]; } - 224 [label="Jump: ^getModifierList when (this@R|/FirModifierList.Companion.getModifierList|) { + 227 [label="Jump: ^getModifierList when (this@R|/FirModifierList.Companion.getModifierList|) { ==($subj$, Null(null)) -> { Null(null) } @@ -681,10 +684,10 @@ digraph kt44814_kt { } } [3]"]; - 225 [label="Stub [3]" style="filled" fillcolor=gray]; - 226 [label="Exit block [3]" style="filled" fillcolor=gray]; + 228 [label="Stub [3]" style="filled" fillcolor=gray]; + 229 [label="Exit block [3]" style="filled" fillcolor=gray]; } - 227 [label="Exit function getModifierList [3]" style="filled" fillcolor=red]; + 230 [label="Exit function getModifierList [3]" style="filled" fillcolor=red]; } 169 -> {170}; 170 -> {171}; @@ -693,131 +696,134 @@ digraph kt44814_kt { 173 -> {174}; 174 -> {175}; 175 -> {176}; - 176 -> {218 177}; - 177 -> {178}; + 176 -> {177}; + 177 -> {221 178}; 178 -> {179}; - 179 -> {204 180}; + 179 -> {180}; 180 -> {181}; - 181 -> {182}; + 181 -> {207 182}; 182 -> {183}; 183 -> {184}; 184 -> {185}; 185 -> {186}; 186 -> {187}; 187 -> {188}; - 188 -> {234}; - 188 -> {189} [color=red]; - 188 -> {234} [style=dashed]; + 188 -> {189}; 189 -> {190}; 190 -> {191}; - 191 -> {196 192}; + 191 -> {237}; + 191 -> {192} [color=red]; + 191 -> {237} [style=dashed]; 192 -> {193}; 193 -> {194}; - 194 -> {227}; - 194 -> {195} [style=dotted]; - 195 -> {197} [style=dotted]; + 194 -> {199 195}; + 195 -> {196}; 196 -> {197}; - 197 -> {198}; - 198 -> {199}; + 197 -> {230}; + 197 -> {198} [style=dotted]; + 198 -> {200} [style=dotted]; 199 -> {200}; 200 -> {201}; 201 -> {202}; 202 -> {203}; - 203 -> {223}; + 203 -> {204}; 204 -> {205}; 205 -> {206}; - 206 -> {207}; - 207 -> {208 210}; + 206 -> {226}; + 207 -> {208}; 208 -> {209}; 209 -> {210}; - 210 -> {211 215}; + 210 -> {211 213}; 211 -> {212}; - 212 -> {228}; - 212 -> {213} [color=red]; - 212 -> {228} [style=dashed]; - 213 -> {214}; + 212 -> {213}; + 213 -> {214 218}; 214 -> {215}; - 215 -> {216}; + 215 -> {231}; + 215 -> {216} [color=red]; + 215 -> {231} [style=dashed]; 216 -> {217}; - 217 -> {223}; + 217 -> {218}; 218 -> {219}; 219 -> {220}; - 220 -> {221}; + 220 -> {226}; 221 -> {222}; 222 -> {223}; 223 -> {224}; - 224 -> {227}; - 224 -> {225} [style=dotted]; - 225 -> {226} [style=dotted]; - 226 -> {227} [style=dotted]; - 228 -> {229}; - 229 -> {230}; - 230 -> {231}; + 224 -> {225}; + 225 -> {226}; + 226 -> {227}; + 227 -> {230}; + 227 -> {228} [style=dotted]; + 228 -> {229} [style=dotted]; + 229 -> {230} [style=dotted]; 231 -> {232}; 232 -> {233}; - 233 -> {213} [color=green]; - 234 -> {244 235}; + 233 -> {234}; + 234 -> {235}; 235 -> {236}; - 236 -> {237 239}; - 237 -> {238}; + 236 -> {216} [color=green]; + 237 -> {247 238}; 238 -> {239}; - 239 -> {240}; + 239 -> {240 242}; 240 -> {241}; 241 -> {242}; 242 -> {243}; 243 -> {244}; - 244 -> {189} [color=green]; - 244 -> {234} [color=green style=dashed]; + 244 -> {245}; + 245 -> {246}; + 246 -> {247}; + 247 -> {192} [color=green]; + 247 -> {237} [color=green style=dashed]; subgraph cluster_68 { color=red - 245 [label="Enter function boxImpl [3]" style="filled" fillcolor=red]; + 248 [label="Enter function boxImpl [3]" style="filled" fillcolor=red]; subgraph cluster_69 { color=blue - 246 [label="Enter block [3]"]; - 247 [label="Function call: R|/LighterASTNode.LighterASTNode|() [6]"]; - 248 [label="Function call: R|kotlin/collections/listOf|(...) [5]"]; - 249 [label="Function call: R|/LighterASTNode.LighterASTNode|(...) [4]"]; - 250 [label="Function call: R|/FlyweightCapableTreeStructure.FlyweightCapableTreeStructure|() [4]"]; - 251 [label="Function call: R|/FirLightSourceElement.FirLightSourceElement|(...) [3]"]; - 252 [label="Variable declaration: lval sourceElement: R|FirSourceElement?| [3]"]; - 253 [label="Access variable R|/sourceElement| [4]"]; - 254 [label="Function call: (this@R|/FirModifierList.Companion|, R|/sourceElement|).R|/FirModifierList.Companion.getModifierList|() [3]"]; - 255 [label="Variable declaration: lval result: R|FirModifierList?| [3]"]; + 249 [label="Enter block [3]"]; + 250 [label="Function call: R|/LighterASTNode.LighterASTNode|() [6]"]; + 251 [label="Function call: R|kotlin/collections/listOf|(...) [5]"]; + 252 [label="Function call: R|/LighterASTNode.LighterASTNode|(...) [4]"]; + 253 [label="Function call: R|/FlyweightCapableTreeStructure.FlyweightCapableTreeStructure|() [4]"]; + 254 [label="Function call: R|/FirLightSourceElement.FirLightSourceElement|(...) [3]"]; + 255 [label="Variable declaration: lval sourceElement: R|FirSourceElement?| [3]"]; + 256 [label="Access variable R|/sourceElement| [4]"]; + 257 [label="Function call: (this@R|/FirModifierList.Companion|, R|/sourceElement|).R|/FirModifierList.Companion.getModifierList|() [3]"]; + 258 [label="Variable declaration: lval result: R|FirModifierList?| [3]"]; subgraph cluster_70 { color=blue - 256 [label="Enter when [3]"]; + 259 [label="Enter when [3]"]; subgraph cluster_71 { color=blue - 257 [label="Enter when branch condition [4]"]; - 258 [label="Access variable R|/result| [5]"]; - 259 [label="Type operator: (R|/result| is R|FirModifierList.FirLightModifierList|) [5]"]; - 260 [label="Exit when branch condition [4]"]; + 260 [label="Enter when branch condition [4]"]; + 261 [label="Access variable R|/result| [5]"]; + 262 [label="Type operator: (R|/result| is R|FirModifierList.FirLightModifierList|) [5]"]; + 263 [label="Exit when branch condition [4]"]; } subgraph cluster_72 { color=blue - 261 [label="Enter when branch condition else [5]"]; - 262 [label="Exit when branch condition [5]"]; + 264 [label="Enter when branch condition else [5]"]; + 265 [label="Exit when branch condition [5]"]; } - 263 [label="Enter when branch result [6]"]; + 266 [label="Enter when branch result [6]"]; subgraph cluster_73 { color=blue - 264 [label="Enter block [6]"]; - 265 [label="Const: String(Fail) [6]"]; - 266 [label="Exit block [6]"]; + 267 [label="Enter block [6]"]; + 268 [label="Const: String(Fail) [6]"]; + 269 [label="Exit block [6]"]; } - 267 [label="Exit when branch result [5]"]; - 268 [label="Enter when branch result [5]"]; + 270 [label="Exit when branch result [5]"]; + 271 [label="Enter when branch result [5]"]; subgraph cluster_74 { color=blue - 269 [label="Enter block [5]"]; - 270 [label="Const: String(OK) [5]"]; - 271 [label="Exit block [5]"]; + 272 [label="Enter block [5]"]; + 273 [label="Const: String(OK) [5]"]; + 274 [label="Exit block [5]"]; } - 272 [label="Exit when branch result [4]"]; - 273 [label="Exit when [3]"]; + 275 [label="Exit when branch result [4]"]; + 276 [label="Exit when [3]"]; } - 274 [label="Jump: ^boxImpl when () { + 277 [label="Jump: ^boxImpl when () { (R|/result| is R|FirModifierList.FirLightModifierList|) -> { String(OK) } @@ -826,14 +832,11 @@ digraph kt44814_kt { } } [3]"]; - 275 [label="Stub [3]" style="filled" fillcolor=gray]; - 276 [label="Exit block [3]" style="filled" fillcolor=gray]; + 278 [label="Stub [3]" style="filled" fillcolor=gray]; + 279 [label="Exit block [3]" style="filled" fillcolor=gray]; } - 277 [label="Exit function boxImpl [3]" style="filled" fillcolor=red]; + 280 [label="Exit function boxImpl [3]" style="filled" fillcolor=red]; } - 245 -> {246}; - 246 -> {247}; - 247 -> {248}; 248 -> {249}; 249 -> {250}; 250 -> {251}; @@ -846,64 +849,67 @@ digraph kt44814_kt { 257 -> {258}; 258 -> {259}; 259 -> {260}; - 260 -> {268 261}; + 260 -> {261}; 261 -> {262}; 262 -> {263}; - 263 -> {264}; + 263 -> {271 264}; 264 -> {265}; 265 -> {266}; 266 -> {267}; - 267 -> {273}; + 267 -> {268}; 268 -> {269}; 269 -> {270}; - 270 -> {271}; + 270 -> {276}; 271 -> {272}; 272 -> {273}; 273 -> {274}; - 274 -> {277}; - 274 -> {275} [style=dotted]; - 275 -> {276} [style=dotted]; - 276 -> {277} [style=dotted]; + 274 -> {275}; + 275 -> {276}; + 276 -> {277}; + 277 -> {280}; + 277 -> {278} [style=dotted]; + 278 -> {279} [style=dotted]; + 279 -> {280} [style=dotted]; subgraph cluster_75 { color=red - 278 [label="Enter class Companion [2]" style="filled" fillcolor=red]; - 279 [label="Exit class Companion [2]" style="filled" fillcolor=red]; + 281 [label="Enter class Companion [2]" style="filled" fillcolor=red]; + 282 [label="Exit class Companion [2]" style="filled" fillcolor=red]; } - 278 -> {279} [color=green]; + 281 -> {282} [color=green]; subgraph cluster_76 { color=red - 280 [label="Enter class FirModifierList [1]" style="filled" fillcolor=red]; - 281 [label="Part of class initialization [1]"]; - 282 [label="Exit class FirModifierList [1]" style="filled" fillcolor=red]; + 283 [label="Enter class FirModifierList [1]" style="filled" fillcolor=red]; + 284 [label="Part of class initialization [1]"]; + 285 [label="Exit class FirModifierList [1]" style="filled" fillcolor=red]; } - 280 -> {281} [color=green]; - 281 -> {282} [style=dotted]; - 281 -> {141} [color=green]; - 281 -> {141} [style=dashed]; + 283 -> {284} [color=green]; + 284 -> {285} [style=dotted]; + 284 -> {141} [color=green]; + 284 -> {141} [style=dashed]; subgraph cluster_77 { color=red - 283 [label="Enter function box [1]" style="filled" fillcolor=red]; + 286 [label="Enter function box [1]" style="filled" fillcolor=red]; subgraph cluster_78 { color=blue - 284 [label="Enter block [1]"]; - 285 [label="Access qualifier /FirModifierList [2]"]; - 286 [label="Function call: Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"]; - 287 [label="Jump: ^box Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"]; - 288 [label="Stub [1]" style="filled" fillcolor=gray]; - 289 [label="Exit block [1]" style="filled" fillcolor=gray]; + 287 [label="Enter block [1]"]; + 288 [label="Access qualifier /FirModifierList [2]"]; + 289 [label="Function call: Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"]; + 290 [label="Jump: ^box Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"]; + 291 [label="Stub [1]" style="filled" fillcolor=gray]; + 292 [label="Exit block [1]" style="filled" fillcolor=gray]; } - 290 [label="Exit function box [1]" style="filled" fillcolor=red]; + 293 [label="Exit function box [1]" style="filled" fillcolor=red]; } - 283 -> {284}; - 284 -> {285}; - 285 -> {286}; 286 -> {287}; - 287 -> {290}; - 287 -> {288} [style=dotted]; - 288 -> {289} [style=dotted]; - 289 -> {290} [style=dotted]; + 287 -> {288}; + 288 -> {289}; + 289 -> {290}; + 290 -> {293}; + 290 -> {291} [style=dotted]; + 291 -> {292} [style=dotted]; + 292 -> {293} [style=dotted]; } diff --git a/compiler/testData/codegen/box/when/whenSubjectVariable/ieee754EqualityWithSmartCast.kt b/compiler/testData/codegen/box/when/whenSubjectVariable/ieee754EqualityWithSmartCast.kt index 3c7bb5a78e8..2f5cfe7aa0e 100644 --- a/compiler/testData/codegen/box/when/whenSubjectVariable/ieee754EqualityWithSmartCast.kt +++ b/compiler/testData/codegen/box/when/whenSubjectVariable/ieee754EqualityWithSmartCast.kt @@ -1,6 +1,4 @@ // !LANGUAGE: +VariableDeclarationInWhenSubject +ProperIeee754Comparisons -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: y is Double but not 0.0 val az: Any = -0.0 val afz: Any = -0.0f diff --git a/compiler/testData/diagnostics/tests/when/DuplicatedLabels.fir.kt b/compiler/testData/diagnostics/tests/when/DuplicatedLabels.fir.kt index f459dd47917..4a0f13ae351 100644 --- a/compiler/testData/diagnostics/tests/when/DuplicatedLabels.fir.kt +++ b/compiler/testData/diagnostics/tests/when/DuplicatedLabels.fir.kt @@ -40,7 +40,7 @@ fun third(arg: Any?): Int { is String -> return 0 is Double -> return 1 is Double -> return 2 - null -> return 3 + null -> return 3 !is String -> return 4 else -> return 5 } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/when/kt36818.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/when/kt36818.fir.kt index 16986b18951..82f34f862ac 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/when/kt36818.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/when/kt36818.fir.kt @@ -1,7 +1,7 @@ fun main(x1: Double?, range: ClosedRange) { when (x1) { null -> throw Exception() - in range -> {} // error, no smartcast from previous branch, OK in OI + in range -> {} // error, no smartcast from previous branch, OK in OI } when { diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.ir.txt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.ir.txt index 4db4c8cb250..d81d584b822 100644 --- a/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.ir.txt +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.ir.txt @@ -75,8 +75,9 @@ FILE fqName: fileName:/whenByFloatingPoint.kt GET_VAR 'val tmp_3: kotlin.Any [val] declared in .testSmartCastInWhenConditionInBranch' type=kotlin.Any origin=null then: CONST Int type=kotlin.Int value=-1 BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp_3: kotlin.Any [val] declared in .testSmartCastInWhenConditionInBranch' type=kotlin.Any origin=null + if: CALL 'public final fun ieee754equals (arg0: kotlin.Double?, arg1: kotlin.Double?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'val tmp_3: kotlin.Any [val] declared in .testSmartCastInWhenConditionInBranch' type=kotlin.Any origin=null arg1: CONST Double type=kotlin.Double value=0.0 then: CONST Int type=kotlin.Int value=0 BRANCH diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.kt.txt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.kt.txt index 21932e86fd8..8fbfc26ffdb 100644 --- a/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.kt.txt +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.fir.kt.txt @@ -39,7 +39,7 @@ fun testSmartCastInWhenConditionInBranch(x: Any): Int { val tmp3_subject: Any = x when { tmp3_subject !is Double -> -1 - EQEQ(arg0 = tmp3_subject, arg1 = 0.0) -> 0 + ieee754equals(arg0 = tmp3_subject /*as Double */, arg1 = 0.0) -> 0 else -> 1 } } @@ -77,3 +77,4 @@ fun testWithPrematureExitInConditionSubexpression(x: Any): Int { } } } + diff --git a/compiler/testData/ir/irText/expressions/when.fir.ir.txt b/compiler/testData/ir/irText/expressions/when.fir.ir.txt index a253e1094fe..7b3853e0656 100644 --- a/compiler/testData/ir/irText/expressions/when.fir.ir.txt +++ b/compiler/testData/ir/irText/expressions/when.fir.ir.txt @@ -46,10 +46,11 @@ FILE fqName: fileName:/when.kt then: CONST String type=kotlin.String value="!Number" BRANCH if: CALL 'public final fun contains (element: T of kotlin.collections.CollectionsKt.contains): kotlin.Boolean [operator] declared in kotlin.collections.CollectionsKt' type=kotlin.Boolean origin=IN - : kotlin.Any? + : kotlin.Number $receiver: CALL 'public final fun setOf (): kotlin.collections.Set [inline] declared in kotlin.collections.SetsKt' type=kotlin.collections.Set origin=null : kotlin.Nothing - element: GET_VAR 'val tmp_0: kotlin.Any? [val] declared in .testWithSubject' type=kotlin.Any? origin=null + element: TYPE_OP type=kotlin.Number origin=IMPLICIT_CAST typeOperand=kotlin.Number + GET_VAR 'val tmp_0: kotlin.Any? [val] declared in .testWithSubject' type=kotlin.Any? origin=null then: CONST String type=kotlin.String value="nothingness?" BRANCH if: CONST Boolean type=kotlin.Boolean value=true diff --git a/compiler/testData/ir/irText/expressions/when.fir.kt.txt b/compiler/testData/ir/irText/expressions/when.fir.kt.txt index 2df62c95bd2..e2c5261800d 100644 --- a/compiler/testData/ir/irText/expressions/when.fir.kt.txt +++ b/compiler/testData/ir/irText/expressions/when.fir.kt.txt @@ -15,7 +15,7 @@ fun testWithSubject(x: Any?): String { EQEQ(arg0 = tmp0_subject, arg1 = A) -> "A" tmp0_subject is String -> "String" tmp0_subject !is Number -> "!Number" - setOf().contains(element = tmp0_subject) -> "nothingness?" + setOf().contains(element = tmp0_subject /*as Number */) -> "nothingness?" else -> "something" } } @@ -61,3 +61,4 @@ fun testComma(x: Int): String { } } } + diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/exhaustive-when-expressions/p-2/pos/7.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/exhaustive-when-expressions/p-2/pos/7.1.fir.kt index 679d7850567..94eb7910223 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/exhaustive-when-expressions/p-2/pos/7.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/exhaustive-when-expressions/p-2/pos/7.1.fir.kt @@ -62,7 +62,7 @@ fun case_7(value_1: SealedClassEmpty): String = when (value_1) { * ISSUES: KT-22996 */ fun case_8(value: SealedClass?): String = when (value) { - is SealedChild1, !is SealedChild3?, is SealedChild3? -> "" + is SealedChild1, !is SealedChild3?, is SealedChild3? -> "" } /* @@ -72,5 +72,5 @@ fun case_8(value: SealedClass?): String = when (value) { */ fun case_9(value: SealedClass?): String = when (value) { is SealedChild1, !is SealedChild3 -> "" - is SealedChild3? -> "" + is SealedChild3? -> "" } diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.fir.kt index 4505fd8624c..42086c467b8 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.fir.kt @@ -14,8 +14,8 @@ fun case_1(value_1: SealedClass) = when (value_1) { */ fun case_2(value_1: SealedClass?): String = when (value_1) { !is SealedChild2 -> "" // including null - is SealedChild2 -> "" - null -> "" // redundant + is SealedChild2 -> "" + null -> "" // redundant } // TESTCASE NUMBER: 3 @@ -33,7 +33,7 @@ fun case_3(value_1: SealedClass?): String = when (value_1) { fun case_4(value_1: SealedClass?) { when (value_1) { !is SealedChild2 -> {} // including null - is SealedChild2? -> {} // redundant nullable type check + is SealedChild2? -> {} // redundant nullable type check } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.4.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.4.fir.kt index f5f71664c0b..3b9c1973a4e 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.4.fir.kt @@ -3,7 +3,7 @@ // TESTCASE NUMBER: 1 fun case_1(value_1: SealedClass): String = when (value_1) { is SealedChild1, !is SealedChild3 -> "" - is SealedChild3 -> "" + is SealedChild3 -> "" } // TESTCASE NUMBER: 2 @@ -18,7 +18,7 @@ fun case_3(value_1: SealedClass): String = when (value_1) { // TESTCASE NUMBER: 4 fun case_4(value_1: SealedClass): String = when (value_1) { - !is SealedChild1, is SealedChild1 -> "" + !is SealedChild1, is SealedChild1 -> "" } // TESTCASE NUMBER: 5 @@ -34,7 +34,7 @@ fun case_5(value_1: Any?): String = when (value_1) { */ fun case_6(value_1: Any?): String = when (value_1) { is Boolean?, !is SealedChild3 -> "" // double nullable type check in the one branch - is SealedChild3 -> "" + is SealedChild3 -> "" else -> "" } diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.fir.kt index db522d9ec8b..441d7d60a24 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.fir.kt @@ -226,7 +226,7 @@ fun case_23(value_1: Nothing) { // TESTCASE NUMBER: 24 fun case_24(value_1: Nothing?) = when (value_1) { throw Exception(), return "" -> "" - null, return return return "", throw throw throw Exception() -> "" + null, return return return "", throw throw throw Exception() -> "" else -> "" }