[FIR] Fix smartcasts on when subject

This commit is contained in:
Dmitriy Novozhilov
2019-08-23 15:20:09 +03:00
parent 200c13baf5
commit bda8c7ee1c
5 changed files with 737 additions and 1 deletions
@@ -101,11 +101,19 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
// ----------------------------------- Operator call -----------------------------------
private fun FirExpression.getResolvedSymbol(): FirCallableSymbol<*>? {
val expression = (this as? FirWhenSubjectExpression)?.whenSubject?.whenExpression?.let {
it.subjectVariable?.symbol?.let { return it }
it.subject
} ?: this
return expression.toResolvedCallableSymbol() as? FirCallableSymbol<*>
}
override fun exitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall) {
val node = graphBuilder.exitTypeOperatorCall(typeOperatorCall).passFlow(false)
try {
if (typeOperatorCall.operation !in FirOperation.TYPES) return
val symbol: FirCallableSymbol<*> = typeOperatorCall.argument.toResolvedCallableSymbol() as? FirCallableSymbol<*> ?: return
val symbol: FirCallableSymbol<*> = typeOperatorCall.argument.getResolvedSymbol() ?: return
val type = typeOperatorCall.conversionTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
val varVariable = getRealVariable(symbol)
@@ -0,0 +1,514 @@
digraph when_kt {
subgraph foo {
0 [shape=box label="Enter function foo"];
1 [shape=box label="Exit function foo"];
0 -> {1};
}
subgraph bar {
2 [shape=box label="Enter function bar"];
3 [shape=box label="Exit function bar"];
2 -> {3};
}
subgraph test_1 {
4 [shape=box label="Enter function test_1"];
5 [shape=box label="Enter block"];
6 [shape=box label="Enter when"];
7 [shape=box label="Enter when branch condition "];
8 [shape=box label="Access variable R|<local>/x|"];
9 [shape=box label="Type operator: x is A"];
10 [shape=box label="Exit when branch condition"];
11 [shape=box label="Enter block"];
12 [shape=box label="Access variable R|<local>/x|"];
13 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
14 [shape=box label="Exit block"];
15 [shape=box label="Exit when branch result"];
16 [shape=box label="Enter when branch condition "];
17 [shape=box label="Access variable R|<local>/x|"];
18 [shape=box label="Type operator: x is B"];
19 [shape=box label="Exit when branch condition"];
20 [shape=box label="Enter block"];
21 [shape=box label="Access variable R|<local>/x|"];
22 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
23 [shape=box label="Exit block"];
24 [shape=box label="Exit when branch result"];
25 [shape=box label="Enter when branch condition else"];
26 [shape=box label="Exit when branch condition"];
27 [shape=box label="Enter block"];
28 [shape=box label="Exit block"];
29 [shape=box label="Exit when branch result"];
30 [shape=box label="Exit when"];
31 [shape=box label="Enter when"];
32 [shape=box label="Enter when branch condition "];
33 [shape=box label="Access variable R|<local>/x|"];
34 [shape=box label="Type operator: x !is A"];
35 [shape=box label="Exit when branch condition"];
36 [shape=box label="Enter block"];
37 [shape=box label="Exit block"];
38 [shape=box label="Exit when branch result"];
39 [shape=box label="Enter when branch condition "];
40 [shape=box label="Access variable R|<local>/x|"];
41 [shape=box label="Type operator: x !is B"];
42 [shape=box label="Exit when branch condition"];
43 [shape=box label="Enter block"];
44 [shape=box label="Access variable R|<local>/x|"];
45 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
46 [shape=box label="Exit block"];
47 [shape=box label="Exit when branch result"];
48 [shape=box label="Enter when branch condition "];
49 [shape=box label="Access variable R|<local>/x|"];
50 [shape=box label="Type operator: x is Int"];
51 [shape=box label="Exit when branch condition"];
52 [shape=box label="Enter block"];
53 [shape=box label="Access variable R|<local>/x|"];
54 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
55 [shape=box label="Access variable R|<local>/x|"];
56 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
57 [shape=box label="Access variable R|<local>/x|"];
58 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
59 [shape=box label="Exit block"];
60 [shape=box label="Exit when branch result"];
61 [shape=box label="Enter when branch condition else"];
62 [shape=box label="Exit when branch condition"];
63 [shape=box label="Enter block"];
64 [shape=box label="Access variable R|<local>/x|"];
65 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
66 [shape=box label="Access variable R|<local>/x|"];
67 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
68 [shape=box label="Exit block"];
69 [shape=box label="Exit when branch result"];
70 [shape=box label="Exit when"];
71 [shape=box label="Exit block"];
72 [shape=box label="Exit function test_1"];
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8};
8 -> {9};
9 -> {10};
10 -> {11 16};
11 -> {12};
12 -> {13};
13 -> {14};
14 -> {15};
15 -> {30};
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {20 25};
20 -> {21};
21 -> {22};
22 -> {23};
23 -> {24};
24 -> {30};
25 -> {26};
26 -> {27};
27 -> {28};
28 -> {29};
29 -> {30};
30 -> {31};
31 -> {32};
32 -> {33};
33 -> {34};
34 -> {35};
35 -> {36 39};
36 -> {37};
37 -> {38};
38 -> {70};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43 48};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {70};
48 -> {49};
49 -> {50};
50 -> {51};
51 -> {52 61};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {60};
60 -> {70};
61 -> {62};
62 -> {63};
63 -> {64};
64 -> {65};
65 -> {66};
66 -> {67};
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
}
subgraph test_2 {
73 [shape=box label="Enter function test_2"];
74 [shape=box label="Enter block"];
75 [shape=box label="Enter when"];
76 [shape=box label="Access variable R|<local>/x|"];
77 [shape=box label="Enter when branch condition "];
78 [shape=box label="Type operator: A"];
79 [shape=box label="Exit when branch condition"];
80 [shape=box label="Enter block"];
81 [shape=box label="Access variable R|<local>/x|"];
82 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
83 [shape=box label="Exit block"];
84 [shape=box label="Exit when branch result"];
85 [shape=box label="Enter when branch condition "];
86 [shape=box label="Type operator: B"];
87 [shape=box label="Exit when branch condition"];
88 [shape=box label="Enter block"];
89 [shape=box label="Access variable R|<local>/x|"];
90 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
91 [shape=box label="Exit block"];
92 [shape=box label="Exit when branch result"];
93 [shape=box label="Enter when branch condition else"];
94 [shape=box label="Exit when branch condition"];
95 [shape=box label="Enter block"];
96 [shape=box label="Exit block"];
97 [shape=box label="Exit when branch result"];
98 [shape=box label="Exit when"];
99 [shape=box label="Enter when"];
100 [shape=box label="Access variable R|<local>/x|"];
101 [shape=box label="Enter when branch condition "];
102 [shape=box label="Type operator: A"];
103 [shape=box label="Exit when branch condition"];
104 [shape=box label="Enter block"];
105 [shape=box label="Exit block"];
106 [shape=box label="Exit when branch result"];
107 [shape=box label="Enter when branch condition "];
108 [shape=box label="Type operator: B"];
109 [shape=box label="Exit when branch condition"];
110 [shape=box label="Enter block"];
111 [shape=box label="Access variable R|<local>/x|"];
112 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
113 [shape=box label="Exit block"];
114 [shape=box label="Exit when branch result"];
115 [shape=box label="Enter when branch condition "];
116 [shape=box label="Type operator: Int"];
117 [shape=box label="Exit when branch condition"];
118 [shape=box label="Enter block"];
119 [shape=box label="Access variable R|<local>/x|"];
120 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
121 [shape=box label="Access variable R|<local>/x|"];
122 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
123 [shape=box label="Access variable R|<local>/x|"];
124 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
125 [shape=box label="Exit block"];
126 [shape=box label="Exit when branch result"];
127 [shape=box label="Enter when branch condition else"];
128 [shape=box label="Exit when branch condition"];
129 [shape=box label="Enter block"];
130 [shape=box label="Access variable R|<local>/x|"];
131 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
132 [shape=box label="Access variable R|<local>/x|"];
133 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
134 [shape=box label="Exit block"];
135 [shape=box label="Exit when branch result"];
136 [shape=box label="Exit when"];
137 [shape=box label="Exit block"];
138 [shape=box label="Exit function test_2"];
73 -> {74};
74 -> {75};
75 -> {76};
76 -> {77};
77 -> {78};
78 -> {79};
79 -> {80 85};
80 -> {81};
81 -> {82};
82 -> {83};
83 -> {84};
84 -> {98};
85 -> {86};
86 -> {87};
87 -> {88 93};
88 -> {89};
89 -> {90};
90 -> {91};
91 -> {92};
92 -> {98};
93 -> {94};
94 -> {95};
95 -> {96};
96 -> {97};
97 -> {98};
98 -> {99};
99 -> {100};
100 -> {101};
101 -> {102};
102 -> {103};
103 -> {104 107};
104 -> {105};
105 -> {106};
106 -> {136};
107 -> {108};
108 -> {109};
109 -> {110 115};
110 -> {111};
111 -> {112};
112 -> {113};
113 -> {114};
114 -> {136};
115 -> {116};
116 -> {117};
117 -> {118 127};
118 -> {119};
119 -> {120};
120 -> {121};
121 -> {122};
122 -> {123};
123 -> {124};
124 -> {125};
125 -> {126};
126 -> {136};
127 -> {128};
128 -> {129};
129 -> {130};
130 -> {131};
131 -> {132};
132 -> {133};
133 -> {134};
134 -> {135};
135 -> {136};
136 -> {137};
137 -> {138};
}
subgraph test_3 {
139 [shape=box label="Enter function test_3"];
140 [shape=box label="Enter block"];
141 [shape=box label="Enter when"];
142 [shape=box label="Access variable R|<local>/x|"];
143 [shape=box label="Variable declaration: lval y: R|kotlin/Any?|"];
144 [shape=box label="Enter when branch condition "];
145 [shape=box label="Type operator: A"];
146 [shape=box label="Exit when branch condition"];
147 [shape=box label="Enter block"];
148 [shape=box label="Access variable R|<local>/x|"];
149 [shape=box label="Function call: R|<local>/x|.<Unresolved name: foo>#()"];
150 [shape=box label="Access variable R|<local>/y|"];
151 [shape=box label="Function call: R|<local>/y|.R|/A.foo|()"];
152 [shape=box label="Exit block"];
153 [shape=box label="Exit when branch result"];
154 [shape=box label="Enter when branch condition "];
155 [shape=box label="Type operator: B"];
156 [shape=box label="Exit when branch condition"];
157 [shape=box label="Enter block"];
158 [shape=box label="Access variable R|<local>/x|"];
159 [shape=box label="Function call: R|<local>/x|.<Unresolved name: bar>#()"];
160 [shape=box label="Access variable R|<local>/y|"];
161 [shape=box label="Function call: R|<local>/y|.R|/B.bar|()"];
162 [shape=box label="Exit block"];
163 [shape=box label="Exit when branch result"];
164 [shape=box label="Enter when branch condition else"];
165 [shape=box label="Exit when branch condition"];
166 [shape=box label="Enter block"];
167 [shape=box label="Exit block"];
168 [shape=box label="Exit when branch result"];
169 [shape=box label="Exit when"];
170 [shape=box label="Enter when"];
171 [shape=box label="Access variable R|<local>/x|"];
172 [shape=box label="Variable declaration: lval y: R|kotlin/Any?|"];
173 [shape=box label="Enter when branch condition "];
174 [shape=box label="Type operator: A"];
175 [shape=box label="Exit when branch condition"];
176 [shape=box label="Enter block"];
177 [shape=box label="Exit block"];
178 [shape=box label="Exit when branch result"];
179 [shape=box label="Enter when branch condition "];
180 [shape=box label="Type operator: B"];
181 [shape=box label="Exit when branch condition"];
182 [shape=box label="Enter block"];
183 [shape=box label="Access variable R|<local>/x|"];
184 [shape=box label="Function call: R|<local>/x|.<Unresolved name: foo>#()"];
185 [shape=box label="Access variable R|<local>/y|"];
186 [shape=box label="Function call: R|<local>/y|.R|/A.foo|()"];
187 [shape=box label="Exit block"];
188 [shape=box label="Exit when branch result"];
189 [shape=box label="Enter when branch condition "];
190 [shape=box label="Type operator: Int"];
191 [shape=box label="Exit when branch condition"];
192 [shape=box label="Enter block"];
193 [shape=box label="Access variable R|<local>/x|"];
194 [shape=box label="Function call: R|<local>/x|.<Unresolved name: foo>#()"];
195 [shape=box label="Access variable R|<local>/x|"];
196 [shape=box label="Function call: R|<local>/x|.<Unresolved name: bar>#()"];
197 [shape=box label="Access variable R|<local>/x|"];
198 [shape=box label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
199 [shape=box label="Access variable R|<local>/y|"];
200 [shape=box label="Function call: R|<local>/y|.R|/A.foo|()"];
201 [shape=box label="Access variable R|<local>/y|"];
202 [shape=box label="Function call: R|<local>/y|.R|/B.bar|()"];
203 [shape=box label="Access variable R|<local>/y|"];
204 [shape=box label="Function call: R|<local>/y|.R|kotlin/Int.inc|()"];
205 [shape=box label="Exit block"];
206 [shape=box label="Exit when branch result"];
207 [shape=box label="Enter when branch condition else"];
208 [shape=box label="Exit when branch condition"];
209 [shape=box label="Enter block"];
210 [shape=box label="Access variable R|<local>/x|"];
211 [shape=box label="Function call: R|<local>/x|.<Unresolved name: foo>#()"];
212 [shape=box label="Access variable R|<local>/x|"];
213 [shape=box label="Function call: R|<local>/x|.<Unresolved name: bar>#()"];
214 [shape=box label="Access variable R|<local>/y|"];
215 [shape=box label="Function call: R|<local>/y|.R|/A.foo|()"];
216 [shape=box label="Access variable R|<local>/y|"];
217 [shape=box label="Function call: R|<local>/y|.R|/B.bar|()"];
218 [shape=box label="Exit block"];
219 [shape=box label="Exit when branch result"];
220 [shape=box label="Exit when"];
221 [shape=box label="Exit block"];
222 [shape=box label="Exit function test_3"];
139 -> {140};
140 -> {141};
141 -> {142};
142 -> {143};
143 -> {144};
144 -> {145};
145 -> {146};
146 -> {147 154};
147 -> {148};
148 -> {149};
149 -> {150};
150 -> {151};
151 -> {152};
152 -> {153};
153 -> {169};
154 -> {155};
155 -> {156};
156 -> {157 164};
157 -> {158};
158 -> {159};
159 -> {160};
160 -> {161};
161 -> {162};
162 -> {163};
163 -> {169};
164 -> {165};
165 -> {166};
166 -> {167};
167 -> {168};
168 -> {169};
169 -> {170};
170 -> {171};
171 -> {172};
172 -> {173};
173 -> {174};
174 -> {175};
175 -> {176 179};
176 -> {177};
177 -> {178};
178 -> {220};
179 -> {180};
180 -> {181};
181 -> {182 189};
182 -> {183};
183 -> {184};
184 -> {185};
185 -> {186};
186 -> {187};
187 -> {188};
188 -> {220};
189 -> {190};
190 -> {191};
191 -> {192 207};
192 -> {193};
193 -> {194};
194 -> {195};
195 -> {196};
196 -> {197};
197 -> {198};
198 -> {199};
199 -> {200};
200 -> {201};
201 -> {202};
202 -> {203};
203 -> {204};
204 -> {205};
205 -> {206};
206 -> {220};
207 -> {208};
208 -> {209};
209 -> {210};
210 -> {211};
211 -> {212};
212 -> {213};
213 -> {214};
214 -> {215};
215 -> {216};
216 -> {217};
217 -> {218};
218 -> {219};
219 -> {220};
220 -> {221};
221 -> {222};
}
subgraph test_4 {
223 [shape=box label="Enter function test_4"];
224 [shape=box label="Enter block"];
225 [shape=box label="Enter when"];
226 [shape=box label="Access variable R|<local>/x|"];
227 [shape=box label="Type operator: x as Int"];
228 [shape=box label="Enter when branch condition "];
229 [shape=box label="Const: Int(1)"];
230 [shape=box label="Operator =="];
231 [shape=box label="Exit when branch condition"];
232 [shape=box label="Enter block"];
233 [shape=box label="Access variable R|<local>/x|"];
234 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
235 [shape=box label="Exit block"];
236 [shape=box label="Exit when branch result"];
237 [shape=box label="Enter when branch condition else"];
238 [shape=box label="Exit when branch condition"];
239 [shape=box label="Enter block"];
240 [shape=box label="Exit block"];
241 [shape=box label="Exit when branch result"];
242 [shape=box label="Exit when"];
243 [shape=box label="Access variable R|<local>/x|"];
244 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
245 [shape=box label="Exit block"];
246 [shape=box label="Exit function test_4"];
223 -> {224};
224 -> {225};
225 -> {226};
226 -> {227};
227 -> {228};
228 -> {229};
229 -> {230};
230 -> {231};
231 -> {232 237};
232 -> {233};
233 -> {234};
234 -> {235};
235 -> {236};
236 -> {242};
237 -> {238};
238 -> {239};
239 -> {240};
240 -> {241};
241 -> {242};
242 -> {243};
243 -> {244};
244 -> {245};
245 -> {246};
}
}
@@ -0,0 +1,91 @@
interface A {
fun foo()
}
interface B {
fun bar()
}
fun test_1(x: Any?) {
when {
x is A -> x.foo()
x is B -> x.bar()
}
when {
x !is A -> {}
x !is B -> x.foo()
x is Int -> {
x.foo()
x.bar()
x.inc()
}
else -> {
x.foo()
x.bar()
}
}
}
fun test_2(x: Any?) {
when(x) {
is A -> x.foo()
is B -> x.bar()
}
when(x) {
!is A -> {}
!is B -> x.foo()
is Int -> {
x.foo()
x.bar()
x.inc()
}
else -> {
x.foo()
x.bar()
}
}
}
fun test_3(x: Any?) {
when(val y = x) {
is A -> {
x.foo()
y.foo()
}
is B -> {
x.bar()
y.bar()
}
}
when(val y = x) {
!is A -> {}
!is B -> {
x.foo()
y.foo()
}
is Int -> {
x.foo()
x.bar()
x.inc()
y.foo()
y.bar()
y.inc()
}
else -> {
x.foo()
x.bar()
y.foo()
y.bar()
}
}
}
fun test_4(x: Any) {
when (x as Int) {
1 -> x.inc()
}
x.inc()
}
@@ -0,0 +1,118 @@
FILE: when.kt
public abstract interface A : R|kotlin/Any| {
public abstract fun foo(): R|kotlin/Unit|
}
public abstract interface B : R|kotlin/Any| {
public abstract fun bar(): R|kotlin/Unit|
}
public final fun test_1(x: R|kotlin/Any?|): R|kotlin/Unit| {
when () {
(R|<local>/x| is R|A|) -> {
R|<local>/x|.R|/A.foo|()
}
(R|<local>/x| is R|B|) -> {
R|<local>/x|.R|/B.bar|()
}
else -> {
}
}
when () {
(R|<local>/x| !is R|A|) -> {
}
(R|<local>/x| !is R|B|) -> {
R|<local>/x|.R|/A.foo|()
}
(R|<local>/x| is R|kotlin/Int|) -> {
R|<local>/x|.R|/A.foo|()
R|<local>/x|.R|/B.bar|()
R|<local>/x|.R|kotlin/Int.inc|()
}
else -> {
R|<local>/x|.R|/A.foo|()
R|<local>/x|.R|/B.bar|()
}
}
}
public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| {
when (R|<local>/x|) {
($subj$ is R|A|) -> {
R|<local>/x|.R|/A.foo|()
}
($subj$ is R|B|) -> {
R|<local>/x|.R|/B.bar|()
}
else -> {
}
}
when (R|<local>/x|) {
($subj$ !is R|A|) -> {
}
($subj$ !is R|B|) -> {
R|<local>/x|.R|/A.foo|()
}
($subj$ is R|kotlin/Int|) -> {
R|<local>/x|.R|/A.foo|()
R|<local>/x|.R|/B.bar|()
R|<local>/x|.R|kotlin/Int.inc|()
}
else -> {
R|<local>/x|.R|/A.foo|()
R|<local>/x|.R|/B.bar|()
}
}
}
public final fun test_3(x: R|kotlin/Any?|): R|kotlin/Unit| {
when (lval y: R|kotlin/Any?| = R|<local>/x|) {
($subj$ is R|A|) -> {
R|<local>/x|.<Unresolved name: foo>#()
R|<local>/y|.R|/A.foo|()
}
($subj$ is R|B|) -> {
R|<local>/x|.<Unresolved name: bar>#()
R|<local>/y|.R|/B.bar|()
}
else -> {
}
}
when (lval y: R|kotlin/Any?| = R|<local>/x|) {
($subj$ !is R|A|) -> {
}
($subj$ !is R|B|) -> {
R|<local>/x|.<Unresolved name: foo>#()
R|<local>/y|.R|/A.foo|()
}
($subj$ is R|kotlin/Int|) -> {
R|<local>/x|.<Unresolved name: foo>#()
R|<local>/x|.<Unresolved name: bar>#()
R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
R|<local>/y|.R|/A.foo|()
R|<local>/y|.R|/B.bar|()
R|<local>/y|.R|kotlin/Int.inc|()
}
else -> {
R|<local>/x|.<Unresolved name: foo>#()
R|<local>/x|.<Unresolved name: bar>#()
R|<local>/y|.R|/A.foo|()
R|<local>/y|.R|/B.bar|()
}
}
}
public final fun test_4(x: R|kotlin/Any|): R|kotlin/Unit| {
when ((R|<local>/x| as R|kotlin/Int|)) {
==($subj$, Int(1)) -> {
R|<local>/x|.R|kotlin/Int.inc|()
}
else -> {
}
}
R|<local>/x|.R|kotlin/Int.inc|()
}
@@ -118,5 +118,10 @@ public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest {
public void testSimpleIf() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt");
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/smartcasts/when.kt");
}
}
}