From f031b47363e306d2a999f83c79260141ad51dca2 Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Mon, 9 Dec 2019 11:25:19 -0800 Subject: [PATCH] [FIR] Fix issue with multiple smartcasts of `this`. --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 22 +- .../resolve/smartcasts/implicitReceivers.dot | 549 +++++++++++++----- .../resolve/smartcasts/implicitReceivers.kt | 41 +- .../resolve/smartcasts/implicitReceivers.txt | 61 ++ .../src/org/jetbrains/kotlin/fir/Utils.kt | 19 +- 5 files changed, 544 insertions(+), 148 deletions(-) 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 ef04c9e2076..ffd7342a6bb 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 @@ -32,6 +32,8 @@ import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.unwrapSmartcast +import org.jetbrains.kotlin.fir.unwrapWhenSubjectExpression import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -838,23 +840,15 @@ class FirDataFlowAnalyzer(private val components: FirAbstractBodyResolveTransfor private fun getOrCreateSyntheticVariable(fir: FirElement): SyntheticDataFlowVariable = variableStorage.getOrCreateNewSyntheticVariable(fir) - private fun FirElement.unwrapWhenSubjectExpression(): FirElement = if (this is FirWhenSubjectExpression) { - val whenExpression = whenSubject.whenExpression - whenExpression.subjectVariable - ?: whenExpression.subject - ?: throw IllegalStateException("Subject or subject variable must be not null") - } else { - this - } - private fun getOrCreateRealVariable(fir: FirElement): RealDataFlowVariable? { @Suppress("NAME_SHADOWING") - val fir = fir.unwrapWhenSubjectExpression() - if (fir is FirThisReceiverExpressionImpl) { - return variableStorage.getOrCreateNewThisRealVariable(fir.calleeReference.boundSymbol ?: return null) + val fir = fir.unwrapWhenSubjectExpression().unwrapSmartcast() + val symbol = fir.resolvedSymbol ?: return null + return when { + fir is FirThisReceiverExpressionImpl -> variableStorage.getOrCreateNewThisRealVariable(symbol) + symbol is FirVariableSymbol<*> -> variableStorage.getOrCreateNewRealVariable(symbol).variableUnderAlias + else -> null } - val symbol = fir.resolvedSymbol as? FirVariableSymbol<*> ?: return null - return variableStorage.getOrCreateNewRealVariable(symbol).variableUnderAlias } private fun getOrCreateVariable(fir: FirElement): DataFlowVariable { diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.dot b/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.dot index d711997bbc9..f6e517d9e9d 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.dot +++ b/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.dot @@ -21,77 +21,89 @@ digraph implicitReceivers_kt { subgraph cluster_2 { color=red - 4 [label="Enter function with" style="filled" fillcolor=red]; - 5 [label="Exit function with" style="filled" fillcolor=red]; + 4 [label="Enter function " style="filled" fillcolor=red]; + 5 [label="Exit function " style="filled" fillcolor=red]; } 4 -> {5}; subgraph cluster_3 { color=red - 6 [label="Enter function test_1" style="filled" fillcolor=red]; - subgraph cluster_4 { - color=blue - 7 [label="Enter when"]; - subgraph cluster_5 { - color=blue - 8 [label="Enter when branch condition "]; - 9 [label="Access variable this@R|/test_1|"]; - 10 [label="Type operator: this is A"]; - 11 [label="Exit when branch condition"]; - } - subgraph cluster_6 { - color=blue - 12 [label="Enter when branch condition else"]; - 13 [label="Exit when branch condition"]; - } - 14 [label="Enter when branch result"]; - subgraph cluster_7 { - color=blue - 15 [label="Enter block"]; - 16 [label="Access variable this@R|/test_1|"]; - 17 [label="Function call: this@R|/test_1|.#()"]; - 18 [label="Function call: #()"]; - 19 [label="Exit block"]; - } - 20 [label="Exit when branch result"]; - 21 [label="Enter when branch result"]; - subgraph cluster_8 { - color=blue - 22 [label="Enter block"]; - 23 [label="Access variable this@R|/test_1|"]; - 24 [label="Function call: this@R|/test_1|.R|/A.foo|()"]; - 25 [label="Function call: this@R|/A|.R|/A.foo|()"]; - 26 [label="Exit block"]; - } - 27 [label="Exit when branch result"]; - 28 [label="Exit when"]; - } - 29 [label="Access variable this@R|/test_1|"]; - 30 [label="Function call: this@R|/test_1|.#()"]; - 31 [label="Function call: #()"]; - 32 [label="Exit function test_1" style="filled" fillcolor=red]; + 6 [label="Enter function bar" style="filled" fillcolor=red]; + 7 [label="Exit function bar" style="filled" fillcolor=red]; } 6 -> {7}; - 7 -> {8}; + + subgraph cluster_4 { + color=red + 8 [label="Enter function with" style="filled" fillcolor=red]; + 9 [label="Exit function with" style="filled" fillcolor=red]; + } + 8 -> {9}; - 9 -> {10}; + + subgraph cluster_5 { + color=red + 10 [label="Enter function test_1" style="filled" fillcolor=red]; + subgraph cluster_6 { + color=blue + 11 [label="Enter when"]; + subgraph cluster_7 { + color=blue + 12 [label="Enter when branch condition "]; + 13 [label="Access variable this@R|/test_1|"]; + 14 [label="Type operator: this is A"]; + 15 [label="Exit when branch condition"]; + } + subgraph cluster_8 { + color=blue + 16 [label="Enter when branch condition else"]; + 17 [label="Exit when branch condition"]; + } + 18 [label="Enter when branch result"]; + subgraph cluster_9 { + color=blue + 19 [label="Enter block"]; + 20 [label="Access variable this@R|/test_1|"]; + 21 [label="Function call: this@R|/test_1|.#()"]; + 22 [label="Function call: #()"]; + 23 [label="Exit block"]; + } + 24 [label="Exit when branch result"]; + 25 [label="Enter when branch result"]; + subgraph cluster_10 { + color=blue + 26 [label="Enter block"]; + 27 [label="Access variable this@R|/test_1|"]; + 28 [label="Function call: this@R|/test_1|.R|/A.foo|()"]; + 29 [label="Function call: this@R|/A|.R|/A.foo|()"]; + 30 [label="Exit block"]; + } + 31 [label="Exit when branch result"]; + 32 [label="Exit when"]; + } + 33 [label="Access variable this@R|/test_1|"]; + 34 [label="Function call: this@R|/test_1|.#()"]; + 35 [label="Function call: #()"]; + 36 [label="Exit function test_1" style="filled" fillcolor=red]; + } + 10 -> {11}; - 11 -> {21 12}; + 11 -> {12}; 12 -> {13}; 13 -> {14}; 14 -> {15}; - 15 -> {16}; + 15 -> {25 16}; 16 -> {17}; 17 -> {18}; 18 -> {19}; 19 -> {20}; - 20 -> {28}; + 20 -> {21}; 21 -> {22}; 22 -> {23}; 23 -> {24}; - 24 -> {25}; + 24 -> {32}; 25 -> {26}; 26 -> {27}; 27 -> {28}; @@ -99,72 +111,72 @@ digraph implicitReceivers_kt { 29 -> {30}; 30 -> {31}; 31 -> {32}; - - subgraph cluster_9 { - color=red - 33 [label="Enter function test_2" style="filled" fillcolor=red]; - subgraph cluster_10 { - color=blue - 34 [label="Enter when"]; - subgraph cluster_11 { - color=blue - 35 [label="Enter when branch condition "]; - 36 [label="Access variable this@R|/test_2|"]; - 37 [label="Type operator: this !is A"]; - 38 [label="Exit when branch condition"]; - } - subgraph cluster_12 { - color=blue - 39 [label="Enter when branch condition else"]; - 40 [label="Exit when branch condition"]; - } - 41 [label="Enter when branch result"]; - subgraph cluster_13 { - color=blue - 42 [label="Enter block"]; - 43 [label="Access variable this@R|/test_2|"]; - 44 [label="Function call: this@R|/test_2|.R|/A.foo|()"]; - 45 [label="Function call: this@R|/A|.R|/A.foo|()"]; - 46 [label="Exit block"]; - } - 47 [label="Exit when branch result"]; - 48 [label="Enter when branch result"]; - subgraph cluster_14 { - color=blue - 49 [label="Enter block"]; - 50 [label="Access variable this@R|/test_2|"]; - 51 [label="Function call: this@R|/test_2|.#()"]; - 52 [label="Function call: #()"]; - 53 [label="Exit block"]; - } - 54 [label="Exit when branch result"]; - 55 [label="Exit when"]; - } - 56 [label="Access variable this@R|/test_2|"]; - 57 [label="Function call: this@R|/test_2|.#()"]; - 58 [label="Function call: #()"]; - 59 [label="Exit function test_2" style="filled" fillcolor=red]; - } - + 32 -> {33}; 33 -> {34}; 34 -> {35}; 35 -> {36}; - 36 -> {37}; + + subgraph cluster_11 { + color=red + 37 [label="Enter function test_2" style="filled" fillcolor=red]; + subgraph cluster_12 { + color=blue + 38 [label="Enter when"]; + subgraph cluster_13 { + color=blue + 39 [label="Enter when branch condition "]; + 40 [label="Access variable this@R|/test_2|"]; + 41 [label="Type operator: this !is A"]; + 42 [label="Exit when branch condition"]; + } + subgraph cluster_14 { + color=blue + 43 [label="Enter when branch condition else"]; + 44 [label="Exit when branch condition"]; + } + 45 [label="Enter when branch result"]; + subgraph cluster_15 { + color=blue + 46 [label="Enter block"]; + 47 [label="Access variable this@R|/test_2|"]; + 48 [label="Function call: this@R|/test_2|.R|/A.foo|()"]; + 49 [label="Function call: this@R|/A|.R|/A.foo|()"]; + 50 [label="Exit block"]; + } + 51 [label="Exit when branch result"]; + 52 [label="Enter when branch result"]; + subgraph cluster_16 { + color=blue + 53 [label="Enter block"]; + 54 [label="Access variable this@R|/test_2|"]; + 55 [label="Function call: this@R|/test_2|.#()"]; + 56 [label="Function call: #()"]; + 57 [label="Exit block"]; + } + 58 [label="Exit when branch result"]; + 59 [label="Exit when"]; + } + 60 [label="Access variable this@R|/test_2|"]; + 61 [label="Function call: this@R|/test_2|.#()"]; + 62 [label="Function call: #()"]; + 63 [label="Exit function test_2" style="filled" fillcolor=red]; + } + 37 -> {38}; - 38 -> {48 39}; + 38 -> {39}; 39 -> {40}; 40 -> {41}; 41 -> {42}; - 42 -> {43}; + 42 -> {52 43}; 43 -> {44}; 44 -> {45}; 45 -> {46}; 46 -> {47}; - 47 -> {55}; + 47 -> {48}; 48 -> {49}; 49 -> {50}; 50 -> {51}; - 51 -> {52}; + 51 -> {59}; 52 -> {53}; 53 -> {54}; 54 -> {55}; @@ -172,41 +184,45 @@ digraph implicitReceivers_kt { 56 -> {57}; 57 -> {58}; 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; - subgraph cluster_15 { + subgraph cluster_17 { color=red - 60 [label="Enter function test_3" style="filled" fillcolor=red]; - 61 [label="Access variable R|/a|"]; - subgraph cluster_16 { + 64 [label="Enter function test_3" style="filled" fillcolor=red]; + 65 [label="Access variable R|/a|"]; + subgraph cluster_18 { color=blue - 62 [label="Enter function anonymousFunction"]; - 63 [label="Access variable R|/b|"]; - subgraph cluster_17 { + 66 [label="Enter function anonymousFunction"]; + 67 [label="Access variable R|/b|"]; + subgraph cluster_19 { color=blue - 64 [label="Enter function anonymousFunction"]; - 65 [label="Access variable R|/c|"]; - subgraph cluster_18 { + 68 [label="Enter function anonymousFunction"]; + 69 [label="Access variable R|/c|"]; + subgraph cluster_20 { color=blue - 66 [label="Enter function anonymousFunction"]; - 67 [label="Access variable this@R|special/anonymous|"]; - 68 [label="Type operator: this@wb as A"]; - 69 [label="Access variable this@R|special/anonymous|"]; - 70 [label="Function call: this@R|special/anonymous|.R|/A.foo|()"]; - 71 [label="Function call: this@R|/A|.R|/A.foo|()"]; - 72 [label="Exit function anonymousFunction"]; + 70 [label="Enter function anonymousFunction"]; + 71 [label="Access variable this@R|special/anonymous|"]; + 72 [label="Type operator: this@wb as A"]; + 73 [label="Access variable this@R|special/anonymous|"]; + 74 [label="Function call: this@R|special/anonymous|.R|/A.foo|()"]; + 75 [label="Function call: this@R|/A|.R|/A.foo|()"]; + 76 [label="Exit function anonymousFunction"]; } - 73 [label="Function call: R|kotlin/with|(R|/c|, = wc@fun R|kotlin/Any|.(): R|kotlin/Unit| { + 77 [label="Function call: R|kotlin/with|(R|/c|, = wc@fun R|kotlin/Any|.(): R|kotlin/Unit| { (this@R|special/anonymous| as R|A|) this@R|special/anonymous|.R|/A.foo|() this@R|/A|.R|/A.foo|() } )"]; - 74 [label="Access variable this@R|special/anonymous|"]; - 75 [label="Function call: this@R|special/anonymous|.R|/A.foo|()"]; - 76 [label="Function call: this@R|/A|.R|/A.foo|()"]; - 77 [label="Exit function anonymousFunction"]; + 78 [label="Access variable this@R|special/anonymous|"]; + 79 [label="Function call: this@R|special/anonymous|.R|/A.foo|()"]; + 80 [label="Function call: this@R|/A|.R|/A.foo|()"]; + 81 [label="Exit function anonymousFunction"]; } - 78 [label="Function call: R|kotlin/with|(R|/b|, = wb@fun R|kotlin/Any|.(): R|kotlin/Unit| { + 82 [label="Function call: R|kotlin/with|(R|/b|, = wb@fun R|kotlin/Any|.(): R|kotlin/Unit| { R|kotlin/with|(R|/c|, = wc@fun R|kotlin/Any|.(): R|kotlin/Unit| { (this@R|special/anonymous| as R|A|) this@R|special/anonymous|.R|/A.foo|() @@ -217,9 +233,9 @@ digraph implicitReceivers_kt { this@R|/A|.R|/A.foo|() } )"]; - 79 [label="Exit function anonymousFunction"]; + 83 [label="Exit function anonymousFunction"]; } - 80 [label="Function call: R|kotlin/with|(R|/a|, = wa@fun R|kotlin/Any|.(): R|kotlin/Unit| { + 84 [label="Function call: R|kotlin/with|(R|/a|, = wa@fun R|kotlin/Any|.(): R|kotlin/Unit| { R|kotlin/with|(R|/b|, = wb@fun R|kotlin/Any|.(): R|kotlin/Unit| { R|kotlin/with|(R|/c|, = wc@fun R|kotlin/Any|.(): R|kotlin/Unit| { (this@R|special/anonymous| as R|A|) @@ -233,13 +249,9 @@ digraph implicitReceivers_kt { ) } )"]; - 81 [label="Exit function test_3" style="filled" fillcolor=red]; + 85 [label="Exit function test_3" style="filled" fillcolor=red]; } - 60 -> {61}; - 61 -> {62}; - 62 -> {63}; - 63 -> {64}; 64 -> {65}; 65 -> {66}; 66 -> {67}; @@ -257,5 +269,278 @@ digraph implicitReceivers_kt { 78 -> {79}; 79 -> {80}; 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + + subgraph cluster_21 { + color=red + 86 [label="Enter function test_4" style="filled" fillcolor=red]; + subgraph cluster_22 { + color=blue + 87 [label="Enter when"]; + subgraph cluster_23 { + color=blue + 88 [label="Enter when branch condition "]; + 89 [label="Access variable this@R|/test_4|"]; + 90 [label="Type operator: this !is A"]; + 91 [label="Exit when branch condition"]; + } + subgraph cluster_24 { + color=blue + 92 [label="Enter when branch condition else"]; + 93 [label="Exit when branch condition"]; + } + 94 [label="Enter when branch result"]; + subgraph cluster_25 { + color=blue + 95 [label="Enter block"]; + subgraph cluster_26 { + color=blue + 96 [label="Enter when"]; + subgraph cluster_27 { + color=blue + 97 [label="Enter when branch condition "]; + 98 [label="Access variable this@R|/test_4|"]; + 99 [label="Type operator: this !is B"]; + 100 [label="Exit when branch condition"]; + } + subgraph cluster_28 { + color=blue + 101 [label="Enter when branch condition else"]; + 102 [label="Exit when branch condition"]; + } + 103 [label="Enter when branch result"]; + subgraph cluster_29 { + color=blue + 104 [label="Enter block"]; + 105 [label="Access variable this@R|/test_4|"]; + 106 [label="Function call: this@R|/test_4|.R|/A.foo|()"]; + 107 [label="Function call: this@R|/A|.R|/A.foo|()"]; + 108 [label="Access variable this@R|/test_4|"]; + 109 [label="Function call: this@R|/test_4|.R|/B.bar|()"]; + 110 [label="Function call: this@R|/B|.R|/B.bar|()"]; + 111 [label="Exit block"]; + } + 112 [label="Exit when branch result"]; + 113 [label="Enter when branch result"]; + subgraph cluster_30 { + color=blue + 114 [label="Enter block"]; + 115 [label="Access variable this@R|/test_4|"]; + 116 [label="Function call: this@R|/test_4|.#()"]; + 117 [label="Function call: #()"]; + 118 [label="Access variable this@R|/test_4|"]; + 119 [label="Function call: this@R|/test_4|.R|/A.foo|()"]; + 120 [label="Function call: this@R|/A|.R|/A.foo|()"]; + 121 [label="Exit block"]; + } + 122 [label="Exit when branch result"]; + 123 [label="Exit when"]; + } + 124 [label="Exit block"]; + } + 125 [label="Exit when branch result"]; + 126 [label="Enter when branch result"]; + subgraph cluster_31 { + color=blue + 127 [label="Enter block"]; + 128 [label="Access variable this@R|/test_4|"]; + 129 [label="Function call: this@R|/test_4|.#()"]; + 130 [label="Function call: #()"]; + 131 [label="Access variable this@R|/test_4|"]; + 132 [label="Function call: this@R|/test_4|.#()"]; + 133 [label="Function call: #()"]; + 134 [label="Exit block"]; + } + 135 [label="Exit when branch result"]; + 136 [label="Exit when"]; + } + 137 [label="Access variable this@R|/test_4|"]; + 138 [label="Function call: this@R|/test_4|.#()"]; + 139 [label="Function call: #()"]; + 140 [label="Access variable this@R|/test_4|"]; + 141 [label="Function call: this@R|/test_4|.#()"]; + 142 [label="Function call: #()"]; + 143 [label="Exit function test_4" style="filled" fillcolor=red]; + } + + 86 -> {87}; + 87 -> {88}; + 88 -> {89}; + 89 -> {90}; + 90 -> {91}; + 91 -> {126 92}; + 92 -> {93}; + 93 -> {94}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {100}; + 100 -> {113 101}; + 101 -> {102}; + 102 -> {103}; + 103 -> {104}; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {110}; + 110 -> {111}; + 111 -> {112}; + 112 -> {123}; + 113 -> {114}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {119}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {136}; + 126 -> {127}; + 127 -> {128}; + 128 -> {129}; + 129 -> {130}; + 130 -> {131}; + 131 -> {132}; + 132 -> {133}; + 133 -> {134}; + 134 -> {135}; + 135 -> {136}; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; + 139 -> {140}; + 140 -> {141}; + 141 -> {142}; + 142 -> {143}; + + subgraph cluster_32 { + color=red + 144 [label="Enter function test_5" style="filled" fillcolor=red]; + subgraph cluster_33 { + color=blue + 145 [label="Enter when"]; + subgraph cluster_34 { + color=blue + 146 [label="Enter when branch condition "]; + 147 [label="Access variable this@R|/test_5|"]; + 148 [label="Type operator: this is List<*>"]; + 149 [label="Exit when branch condition"]; + } + subgraph cluster_35 { + color=blue + 150 [label="Enter when branch condition "]; + 151 [label="Access variable this@R|/test_5|"]; + 152 [label="Type operator: this is String"]; + 153 [label="Exit when branch condition"]; + } + subgraph cluster_36 { + color=blue + 154 [label="Enter when branch condition else"]; + 155 [label="Exit when branch condition"]; + } + 156 [label="Enter when branch result"]; + subgraph cluster_37 { + color=blue + 157 [label="Enter block"]; + 158 [label="Const: Int(0)"]; + 159 [label="Exit block"]; + } + 160 [label="Exit when branch result"]; + 161 [label="Enter when branch result"]; + subgraph cluster_38 { + color=blue + 162 [label="Enter block"]; + 163 [label="Access variable R|kotlin/String.length|"]; + 164 [label="Exit block"]; + } + 165 [label="Exit when branch result"]; + 166 [label="Enter when branch result"]; + subgraph cluster_39 { + color=blue + 167 [label="Enter block"]; + 168 [label="Access variable R|kotlin/collections/List.size|"]; + 169 [label="Exit block"]; + } + 170 [label="Exit when branch result"]; + 171 [label="Exit when"]; + } + 172 [label="Jump: ^test_5 when () { + (this@R|/test_5| is R|kotlin/collections/List<*>|) -> { + this@R|kotlin/collections/List|.R|kotlin/collections/List.size| + } + (this@R|/test_5| is R|kotlin/String|) -> { + this@R|kotlin/String|.R|kotlin/String.length| + } + else -> { + Int(0) + } +} +"]; + 173 [label="Stub" style="filled" fillcolor=gray]; + 174 [label="Exit function test_5" style="filled" fillcolor=red]; + } + + 144 -> {145}; + 145 -> {146}; + 146 -> {147}; + 147 -> {148}; + 148 -> {149}; + 149 -> {166 150}; + 150 -> {151}; + 151 -> {152}; + 152 -> {153}; + 153 -> {161 154}; + 154 -> {155}; + 155 -> {156}; + 156 -> {157}; + 157 -> {158}; + 158 -> {159}; + 159 -> {160}; + 160 -> {171}; + 161 -> {162}; + 162 -> {163}; + 163 -> {164}; + 164 -> {165}; + 165 -> {171}; + 166 -> {167}; + 167 -> {168}; + 168 -> {169}; + 169 -> {170}; + 170 -> {171}; + 171 -> {172}; + 172 -> {174}; + 172 -> {173} [style=dotted]; + 173 -> {174} [style=dotted]; + + subgraph cluster_40 { + color=red + 175 [label="Enter function test_6" style="filled" fillcolor=red]; + 176 [label="Access variable this@R|/test_6|"]; + 177 [label="Type operator: this as List<*>"]; + 178 [label="Access variable R|kotlin/collections/List.size|"]; + 179 [label="Access variable this@R|/test_6|"]; + 180 [label="Type operator: this as String"]; + 181 [label="Access variable R|kotlin/String.length|"]; + 182 [label="Exit function test_6" style="filled" fillcolor=red]; + } + + 175 -> {176}; + 176 -> {177}; + 177 -> {178}; + 178 -> {179}; + 179 -> {180}; + 180 -> {181}; + 181 -> {182}; } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.kt b/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.kt index 025bbe2725d..dae3c878b8d 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.kt +++ b/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.kt @@ -2,6 +2,10 @@ class A { fun foo() {} } +class B { + fun bar() {} +} + fun T.with(block: T.() -> Unit) {} fun Any?.test_1() { @@ -28,7 +32,6 @@ fun Any?.test_2() { foo() } - fun test_3(a: Any, b: Any, c: Any) { with(a) wa@{ with(b) wb@{ @@ -41,4 +44,40 @@ fun test_3(a: Any, b: Any, c: Any) { foo() } } +} + +fun Any?.test_4() { + if (this !is A) { + this.foo() + foo() + this.bar() + bar() + } else if (this !is B) { + this.bar() + bar() + this.foo() + foo() + } else { + this.foo() + foo() + this.bar() + bar() + } + this.foo() + foo() + this.bar() + bar() +} + +fun Any.test_5(): Int = when { + this is List<*> -> size + this is String -> length + else -> 0 +} + +fun Any.test_6() { + this as List<*> + size + this as String + length } \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.txt b/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.txt index 69c9a3d1286..765b52656a6 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.txt +++ b/compiler/fir/resolve/testData/resolve/smartcasts/implicitReceivers.txt @@ -7,6 +7,15 @@ FILE: implicitReceivers.kt public final fun foo(): R|kotlin/Unit| { } + } + public final class B : R|kotlin/Any| { + public constructor(): R|B| { + super() + } + + public final fun bar(): R|kotlin/Unit| { + } + } public final fun R|T|.with(block: R|T.() -> kotlin/Unit|): R|kotlin/Unit| { } @@ -56,3 +65,55 @@ FILE: implicitReceivers.kt } ) } + public final fun R|kotlin/Any?|.test_4(): R|kotlin/Unit| { + when () { + (this@R|/test_4| !is R|A|) -> { + this@R|/test_4|.#() + #() + this@R|/test_4|.#() + #() + } + else -> { + when () { + (this@R|/test_4| !is R|B|) -> { + this@R|/test_4|.#() + #() + this@R|/test_4|.R|/A.foo|() + this@R|/A|.R|/A.foo|() + } + else -> { + this@R|/test_4|.R|/A.foo|() + this@R|/A|.R|/A.foo|() + this@R|/test_4|.R|/B.bar|() + this@R|/B|.R|/B.bar|() + } + } + + } + } + + this@R|/test_4|.#() + #() + this@R|/test_4|.#() + #() + } + public final fun R|kotlin/Any|.test_5(): R|kotlin/Int| { + ^test_5 when () { + (this@R|/test_5| is R|kotlin/collections/List<*>|) -> { + this@R|kotlin/collections/List|.R|kotlin/collections/List.size| + } + (this@R|/test_5| is R|kotlin/String|) -> { + this@R|kotlin/String|.R|kotlin/String.length| + } + else -> { + Int(0) + } + } + + } + public final fun R|kotlin/Any|.test_6(): R|kotlin/Unit| { + (this@R|/test_6| as R|kotlin/collections/List<*>|) + this@R|kotlin/collections/List|.R|kotlin/collections/List.size| + (this@R|/test_6| as R|kotlin/String|) + this@R|kotlin/String|.R|kotlin/String.length| + } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt index b4688354929..819d1535f21 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt @@ -8,9 +8,26 @@ package org.jetbrains.kotlin.fir import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast +import org.jetbrains.kotlin.fir.expressions.FirWhenSubjectExpression import org.jetbrains.kotlin.fir.visitors.FirTransformer fun ModuleInfo.dependenciesWithoutSelf(): Sequence = dependencies().asSequence().filter { it != this } // TODO: rewrite -fun FirBlock.returnExpressions(): List = listOfNotNull(statements.lastOrNull() as? FirExpression) \ No newline at end of file +fun FirBlock.returnExpressions(): List = listOfNotNull(statements.lastOrNull() as? FirExpression) + +fun FirElement.unwrapWhenSubjectExpression(): FirElement = if (this is FirWhenSubjectExpression) { + val whenExpression = whenSubject.whenExpression + whenExpression.subjectVariable + ?: whenExpression.subject + ?: throw IllegalStateException("Subject or subject variable must be not null") +} else { + this +} + +tailrec fun FirElement.unwrapSmartcast(): FirElement = if (this is FirExpressionWithSmartcast) { + originalExpression.unwrapSmartcast() +} else { + this +} \ No newline at end of file