[Raw FIR] Build if - else if - else as two nested whens

This is necessary for inference to work like in K1 because we only
add equality constraints from expected types on top-level `when`, not
on nested ones.

#KT-65882
This commit is contained in:
Kirill Rakhman
2024-02-29 14:56:10 +01:00
committed by Space Team
parent 888c1defa0
commit b4413776ab
12 changed files with 390 additions and 338 deletions
@@ -46,11 +46,16 @@ FILE: kt53494.kt
!=(R|<local>/t|, Null(null)) -> {
R|/Wrapped.Wrapped|<R|T? & Any|>(R|<local>/t|)
}
(R|<local>/t| is R|T|) -> {
R|/Wrapped.Wrapped|<R|it(kotlin/Nothing? & T)|>(R|<local>/t|)
}
else -> {
Q|Default|
when () {
(R|<local>/t| is R|T|) -> {
R|/Wrapped.Wrapped|<R|it(kotlin/Nothing? & T)|>(R|<local>/t|)
}
else -> {
Q|Default|
}
}
}
}
@@ -506,151 +506,168 @@ digraph implicitReceivers_kt {
}
subgraph cluster_56 {
color=blue
166 [label="Enter when branch condition "];
167 [label="Access variable this@R|/test_4|"];
168 [label="Smart cast: this@R|/test_4|"];
169 [label="Type operator: (this@R|/test_4| !is R|B|)"];
170 [label="Exit when branch condition"];
166 [label="Enter when branch condition else"];
167 [label="Exit when branch condition"];
}
168 [label="Enter when branch result"];
subgraph cluster_57 {
color=blue
171 [label="Enter when branch condition else"];
172 [label="Exit when branch condition"];
169 [label="Enter block"];
subgraph cluster_58 {
color=blue
170 [label="Enter when"];
subgraph cluster_59 {
color=blue
171 [label="Enter when branch condition "];
172 [label="Access variable this@R|/test_4|"];
173 [label="Smart cast: this@R|/test_4|"];
174 [label="Type operator: (this@R|/test_4| !is R|B|)"];
175 [label="Exit when branch condition"];
}
subgraph cluster_60 {
color=blue
176 [label="Enter when branch condition else"];
177 [label="Exit when branch condition"];
}
178 [label="Enter when branch result"];
subgraph cluster_61 {
color=blue
179 [label="Enter block"];
subgraph cluster_62 {
color=blue
180 [label="Function call arguments enter"];
181 [label="Access variable this@R|/test_4|"];
182 [label="Smart cast: this@R|/test_4|"];
183 [label="Function call arguments exit"];
}
184 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
subgraph cluster_63 {
color=blue
185 [label="Function call arguments enter"];
186 [label="Function call arguments exit"];
}
187 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
subgraph cluster_64 {
color=blue
188 [label="Function call arguments enter"];
189 [label="Access variable this@R|/test_4|"];
190 [label="Smart cast: this@R|/test_4|"];
191 [label="Function call arguments exit"];
}
192 [label="Function call: this@R|/test_4|.R|/B.bar|()" style="filled" fillcolor=yellow];
subgraph cluster_65 {
color=blue
193 [label="Function call arguments enter"];
194 [label="Function call arguments exit"];
}
195 [label="Function call: this@R|/test_4|.R|/B.bar|()" style="filled" fillcolor=yellow];
196 [label="Exit block"];
}
197 [label="Exit when branch result"];
198 [label="Enter when branch result"];
subgraph cluster_66 {
color=blue
199 [label="Enter block"];
subgraph cluster_67 {
color=blue
200 [label="Function call arguments enter"];
201 [label="Access variable this@R|/test_4|"];
202 [label="Smart cast: this@R|/test_4|"];
203 [label="Function call arguments exit"];
}
204 [label="Function call: this@R|/test_4|.<Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_68 {
color=blue
205 [label="Function call arguments enter"];
206 [label="Function call arguments exit"];
}
207 [label="Function call: <Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_69 {
color=blue
208 [label="Function call arguments enter"];
209 [label="Access variable this@R|/test_4|"];
210 [label="Smart cast: this@R|/test_4|"];
211 [label="Function call arguments exit"];
}
212 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
subgraph cluster_70 {
color=blue
213 [label="Function call arguments enter"];
214 [label="Function call arguments exit"];
}
215 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
216 [label="Exit block"];
}
217 [label="Exit when branch result"];
218 [label="Exit when"];
}
219 [label="Exit block"];
}
173 [label="Enter when branch result"];
subgraph cluster_58 {
220 [label="Exit when branch result"];
221 [label="Enter when branch result"];
subgraph cluster_71 {
color=blue
174 [label="Enter block"];
subgraph cluster_59 {
color=blue
175 [label="Function call arguments enter"];
176 [label="Access variable this@R|/test_4|"];
177 [label="Smart cast: this@R|/test_4|"];
178 [label="Function call arguments exit"];
}
179 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
subgraph cluster_60 {
color=blue
180 [label="Function call arguments enter"];
181 [label="Function call arguments exit"];
}
182 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
subgraph cluster_61 {
color=blue
183 [label="Function call arguments enter"];
184 [label="Access variable this@R|/test_4|"];
185 [label="Smart cast: this@R|/test_4|"];
186 [label="Function call arguments exit"];
}
187 [label="Function call: this@R|/test_4|.R|/B.bar|()" style="filled" fillcolor=yellow];
subgraph cluster_62 {
color=blue
188 [label="Function call arguments enter"];
189 [label="Function call arguments exit"];
}
190 [label="Function call: this@R|/test_4|.R|/B.bar|()" style="filled" fillcolor=yellow];
191 [label="Exit block"];
}
192 [label="Exit when branch result"];
193 [label="Enter when branch result"];
subgraph cluster_63 {
color=blue
194 [label="Enter block"];
subgraph cluster_64 {
color=blue
195 [label="Function call arguments enter"];
196 [label="Access variable this@R|/test_4|"];
197 [label="Smart cast: this@R|/test_4|"];
198 [label="Function call arguments exit"];
}
199 [label="Function call: this@R|/test_4|.<Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_65 {
color=blue
200 [label="Function call arguments enter"];
201 [label="Function call arguments exit"];
}
202 [label="Function call: <Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_66 {
color=blue
203 [label="Function call arguments enter"];
204 [label="Access variable this@R|/test_4|"];
205 [label="Smart cast: this@R|/test_4|"];
206 [label="Function call arguments exit"];
}
207 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
subgraph cluster_67 {
color=blue
208 [label="Function call arguments enter"];
209 [label="Function call arguments exit"];
}
210 [label="Function call: this@R|/test_4|.R|/A.foo|()" style="filled" fillcolor=yellow];
211 [label="Exit block"];
}
212 [label="Exit when branch result"];
213 [label="Enter when branch result"];
subgraph cluster_68 {
color=blue
214 [label="Enter block"];
subgraph cluster_69 {
color=blue
215 [label="Function call arguments enter"];
216 [label="Access variable this@R|/test_4|"];
217 [label="Function call arguments exit"];
}
218 [label="Function call: this@R|/test_4|.<Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_70 {
color=blue
219 [label="Function call arguments enter"];
220 [label="Function call arguments exit"];
}
221 [label="Function call: <Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_71 {
color=blue
222 [label="Function call arguments enter"];
223 [label="Access variable this@R|/test_4|"];
224 [label="Function call arguments exit"];
}
225 [label="Function call: this@R|/test_4|.<Unresolved name: bar>#()" style="filled" fillcolor=yellow];
222 [label="Enter block"];
subgraph cluster_72 {
color=blue
226 [label="Function call arguments enter"];
227 [label="Function call arguments exit"];
223 [label="Function call arguments enter"];
224 [label="Access variable this@R|/test_4|"];
225 [label="Function call arguments exit"];
}
228 [label="Function call: <Unresolved name: bar>#()" style="filled" fillcolor=yellow];
229 [label="Exit block"];
226 [label="Function call: this@R|/test_4|.<Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_73 {
color=blue
227 [label="Function call arguments enter"];
228 [label="Function call arguments exit"];
}
229 [label="Function call: <Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_74 {
color=blue
230 [label="Function call arguments enter"];
231 [label="Access variable this@R|/test_4|"];
232 [label="Function call arguments exit"];
}
233 [label="Function call: this@R|/test_4|.<Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_75 {
color=blue
234 [label="Function call arguments enter"];
235 [label="Function call arguments exit"];
}
236 [label="Function call: <Unresolved name: bar>#()" style="filled" fillcolor=yellow];
237 [label="Exit block"];
}
230 [label="Exit when branch result"];
231 [label="Exit when"];
238 [label="Exit when branch result"];
239 [label="Exit when"];
}
subgraph cluster_73 {
color=blue
232 [label="Function call arguments enter"];
233 [label="Access variable this@R|/test_4|"];
234 [label="Function call arguments exit"];
}
235 [label="Function call: this@R|/test_4|.<Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_74 {
color=blue
236 [label="Function call arguments enter"];
237 [label="Function call arguments exit"];
}
238 [label="Function call: <Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_75 {
color=blue
239 [label="Function call arguments enter"];
240 [label="Access variable this@R|/test_4|"];
241 [label="Function call arguments exit"];
}
242 [label="Function call: this@R|/test_4|.<Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_76 {
color=blue
243 [label="Function call arguments enter"];
244 [label="Function call arguments exit"];
240 [label="Function call arguments enter"];
241 [label="Access variable this@R|/test_4|"];
242 [label="Function call arguments exit"];
}
245 [label="Function call: <Unresolved name: bar>#()" style="filled" fillcolor=yellow];
246 [label="Exit block"];
243 [label="Function call: this@R|/test_4|.<Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_77 {
color=blue
244 [label="Function call arguments enter"];
245 [label="Function call arguments exit"];
}
246 [label="Function call: <Unresolved name: foo>#()" style="filled" fillcolor=yellow];
subgraph cluster_78 {
color=blue
247 [label="Function call arguments enter"];
248 [label="Access variable this@R|/test_4|"];
249 [label="Function call arguments exit"];
}
250 [label="Function call: this@R|/test_4|.<Unresolved name: bar>#()" style="filled" fillcolor=yellow];
subgraph cluster_79 {
color=blue
251 [label="Function call arguments enter"];
252 [label="Function call arguments exit"];
}
253 [label="Function call: <Unresolved name: bar>#()" style="filled" fillcolor=yellow];
254 [label="Exit block"];
}
247 [label="Exit function test_4" style="filled" fillcolor=red];
255 [label="Exit function test_4" style="filled" fillcolor=red];
}
159 -> {160};
160 -> {161};
@@ -658,17 +675,17 @@ digraph implicitReceivers_kt {
162 -> {163};
163 -> {164};
164 -> {165};
165 -> {166 213};
165 -> {166 221};
166 -> {167};
167 -> {168};
168 -> {169};
169 -> {170};
170 -> {171 193};
170 -> {171};
171 -> {172};
172 -> {173};
173 -> {174};
174 -> {175};
175 -> {176};
175 -> {176 198};
176 -> {177};
177 -> {178};
178 -> {179};
@@ -685,12 +702,12 @@ digraph implicitReceivers_kt {
189 -> {190};
190 -> {191};
191 -> {192};
192 -> {231};
192 -> {193};
193 -> {194};
194 -> {195};
195 -> {196};
196 -> {197};
197 -> {198};
197 -> {218};
198 -> {199};
199 -> {200};
200 -> {201};
@@ -705,7 +722,7 @@ digraph implicitReceivers_kt {
209 -> {210};
210 -> {211};
211 -> {212};
212 -> {231};
212 -> {213};
213 -> {214};
214 -> {215};
215 -> {216};
@@ -713,7 +730,7 @@ digraph implicitReceivers_kt {
217 -> {218};
218 -> {219};
219 -> {220};
220 -> {221};
220 -> {239};
221 -> {222};
222 -> {223};
223 -> {224};
@@ -740,62 +757,70 @@ digraph implicitReceivers_kt {
244 -> {245};
245 -> {246};
246 -> {247};
247 -> {248};
248 -> {249};
249 -> {250};
250 -> {251};
251 -> {252};
252 -> {253};
253 -> {254};
254 -> {255};
subgraph cluster_77 {
subgraph cluster_80 {
color=red
248 [label="Enter function test_5" style="filled" fillcolor=red];
subgraph cluster_78 {
256 [label="Enter function test_5" style="filled" fillcolor=red];
subgraph cluster_81 {
color=blue
249 [label="Enter block"];
subgraph cluster_79 {
257 [label="Enter block"];
subgraph cluster_82 {
color=blue
250 [label="Enter when"];
subgraph cluster_80 {
color=blue
251 [label="Enter when branch condition "];
252 [label="Access variable this@R|/test_5|"];
253 [label="Type operator: (this@R|/test_5| is R|kotlin/collections/List<*>|)"];
254 [label="Exit when branch condition"];
}
subgraph cluster_81 {
color=blue
255 [label="Enter when branch condition "];
256 [label="Access variable this@R|/test_5|"];
257 [label="Type operator: (this@R|/test_5| is R|kotlin/String|)"];
258 [label="Exit when branch condition"];
}
subgraph cluster_82 {
color=blue
259 [label="Enter when branch condition else"];
260 [label="Exit when branch condition"];
}
261 [label="Enter when branch result"];
258 [label="Enter when"];
subgraph cluster_83 {
color=blue
262 [label="Enter block"];
263 [label="Const: Int(0)"];
264 [label="Exit block"];
259 [label="Enter when branch condition "];
260 [label="Access variable this@R|/test_5|"];
261 [label="Type operator: (this@R|/test_5| is R|kotlin/collections/List<*>|)"];
262 [label="Exit when branch condition"];
}
265 [label="Exit when branch result"];
266 [label="Enter when branch result"];
subgraph cluster_84 {
color=blue
267 [label="Enter block"];
268 [label="Access variable R|kotlin/String.length|"];
269 [label="Exit block"];
263 [label="Enter when branch condition "];
264 [label="Access variable this@R|/test_5|"];
265 [label="Type operator: (this@R|/test_5| is R|kotlin/String|)"];
266 [label="Exit when branch condition"];
}
270 [label="Exit when branch result"];
271 [label="Enter when branch result"];
subgraph cluster_85 {
color=blue
272 [label="Enter block"];
273 [label="Access variable R|SubstitutionOverride<kotlin/collections/List.size: R|kotlin/Int|>|"];
274 [label="Exit block"];
267 [label="Enter when branch condition else"];
268 [label="Exit when branch condition"];
}
275 [label="Exit when branch result"];
276 [label="Exit when"];
269 [label="Enter when branch result"];
subgraph cluster_86 {
color=blue
270 [label="Enter block"];
271 [label="Const: Int(0)"];
272 [label="Exit block"];
}
273 [label="Exit when branch result"];
274 [label="Enter when branch result"];
subgraph cluster_87 {
color=blue
275 [label="Enter block"];
276 [label="Access variable R|kotlin/String.length|"];
277 [label="Exit block"];
}
278 [label="Exit when branch result"];
279 [label="Enter when branch result"];
subgraph cluster_88 {
color=blue
280 [label="Enter block"];
281 [label="Access variable R|SubstitutionOverride<kotlin/collections/List.size: R|kotlin/Int|>|"];
282 [label="Exit block"];
}
283 [label="Exit when branch result"];
284 [label="Exit when"];
}
277 [label="Jump: ^test_5 when () {
285 [label="Jump: ^test_5 when () {
(this@R|/test_5| is R|kotlin/collections/List<*>|) -> {
this@R|/test_5|.R|SubstitutionOverride<kotlin/collections/List.size: R|kotlin/Int|>|
}
@@ -807,71 +832,71 @@ digraph implicitReceivers_kt {
}
}
"];
278 [label="Stub" style="filled" fillcolor=gray];
279 [label="Exit block" style="filled" fillcolor=gray];
286 [label="Stub" style="filled" fillcolor=gray];
287 [label="Exit block" style="filled" fillcolor=gray];
}
280 [label="Exit function test_5" style="filled" fillcolor=red];
288 [label="Exit function test_5" style="filled" fillcolor=red];
}
248 -> {249};
249 -> {250};
250 -> {251};
251 -> {252};
252 -> {253};
253 -> {254};
254 -> {255 271};
255 -> {256};
256 -> {257};
257 -> {258};
258 -> {259 266};
258 -> {259};
259 -> {260};
260 -> {261};
261 -> {262};
262 -> {263};
262 -> {263 279};
263 -> {264};
264 -> {265};
265 -> {276};
266 -> {267};
265 -> {266};
266 -> {267 274};
267 -> {268};
268 -> {269};
269 -> {270};
270 -> {276};
270 -> {271};
271 -> {272};
272 -> {273};
273 -> {274};
273 -> {284};
274 -> {275};
275 -> {276};
276 -> {277};
277 -> {280};
277 -> {278} [style=dotted];
278 -> {279} [style=dotted];
279 -> {280} [style=dotted];
subgraph cluster_86 {
color=red
281 [label="Enter function test_6" style="filled" fillcolor=red];
subgraph cluster_87 {
color=blue
282 [label="Enter block"];
283 [label="Access variable this@R|/test_6|"];
284 [label="Type operator: (this@R|/test_6| as R|kotlin/collections/List<*>|)"];
285 [label="Access variable R|SubstitutionOverride<kotlin/collections/List.size: R|kotlin/Int|>|"];
286 [label="Access variable this@R|/test_6|"];
287 [label="Smart cast: this@R|/test_6|"];
288 [label="Type operator: (this@R|/test_6| as R|kotlin/String|)"];
289 [label="Access variable R|kotlin/String.length|"];
290 [label="Exit block"];
}
291 [label="Exit function test_6" style="filled" fillcolor=red];
}
277 -> {278};
278 -> {284};
279 -> {280};
280 -> {281};
281 -> {282};
282 -> {283};
283 -> {284};
284 -> {285};
285 -> {286};
286 -> {287};
287 -> {288};
288 -> {289};
285 -> {288};
285 -> {286} [style=dotted];
286 -> {287} [style=dotted];
287 -> {288} [style=dotted];
subgraph cluster_89 {
color=red
289 [label="Enter function test_6" style="filled" fillcolor=red];
subgraph cluster_90 {
color=blue
290 [label="Enter block"];
291 [label="Access variable this@R|/test_6|"];
292 [label="Type operator: (this@R|/test_6| as R|kotlin/collections/List<*>|)"];
293 [label="Access variable R|SubstitutionOverride<kotlin/collections/List.size: R|kotlin/Int|>|"];
294 [label="Access variable this@R|/test_6|"];
295 [label="Smart cast: this@R|/test_6|"];
296 [label="Type operator: (this@R|/test_6| as R|kotlin/String|)"];
297 [label="Access variable R|kotlin/String.length|"];
298 [label="Exit block"];
}
299 [label="Exit function test_6" style="filled" fillcolor=red];
}
289 -> {290};
290 -> {291};
291 -> {292};
292 -> {293};
293 -> {294};
294 -> {295};
295 -> {296};
296 -> {297};
297 -> {298};
298 -> {299};
}
@@ -73,17 +73,22 @@ FILE: implicitReceivers.kt
this@R|/test_4|.<Unresolved name: bar>#()
<Unresolved name: bar>#()
}
(this@R|/test_4| !is R|B|) -> {
this@R|/test_4|.<Unresolved name: bar>#()
<Unresolved name: bar>#()
this@R|/test_4|.R|/A.foo|()
this@R|/test_4|.R|/A.foo|()
}
else -> {
this@R|/test_4|.R|/A.foo|()
this@R|/test_4|.R|/A.foo|()
this@R|/test_4|.R|/B.bar|()
this@R|/test_4|.R|/B.bar|()
when () {
(this@R|/test_4| !is R|B|) -> {
this@R|/test_4|.<Unresolved name: bar>#()
<Unresolved name: bar>#()
this@R|/test_4|.R|/A.foo|()
this@R|/test_4|.R|/A.foo|()
}
else -> {
this@R|/test_4|.R|/A.foo|()
this@R|/test_4|.R|/A.foo|()
this@R|/test_4|.R|/B.bar|()
this@R|/test_4|.R|/B.bar|()
}
}
}
}
@@ -1248,14 +1248,17 @@ class Fir2IrVisitor(
if (whenExpression.branches.isEmpty()) {
return@convertWithOffsets IrBlockImpl(startOffset, endOffset, irBuiltIns.unitType, origin)
}
val isProperlyExhaustive = whenExpression.isDeeplyProperlyExhaustive()
val whenExpressionType =
if (whenExpression.isProperlyExhaustive && whenExpression.branches.none {
if (isProperlyExhaustive && whenExpression.branches.none {
it.condition is FirElseIfTrueCondition && it.result.statements.isEmpty()
}) whenExpression.resolvedType else session.builtinTypes.unitType.type
val irBranches = whenExpression.branches.mapTo(mutableListOf()) { branch ->
branch.toIrWhenBranch(whenExpressionType)
}
if (whenExpression.isProperlyExhaustive && whenExpression.branches.none { it.condition is FirElseIfTrueCondition }) {
val irBranches = whenExpression.convertWhenBranchesTo(
mutableListOf(),
whenExpressionType,
flattenElse = origin == IrStatementOrigin.IF,
)
if (isProperlyExhaustive && whenExpression.branches.none { it.condition is FirElseIfTrueCondition }) {
val irResult = IrCallImpl(
startOffset, endOffset, irBuiltIns.nothingType,
irBuiltIns.noWhenBranchMatchedExceptionSymbol,
@@ -1273,6 +1276,57 @@ class Fir2IrVisitor(
}
}
/**
* TODO this shouldn't be required anymore once KT-65997 is fixed.
*/
private fun FirWhenExpression.isDeeplyProperlyExhaustive(): Boolean {
if (!isProperlyExhaustive) {
return false
}
val nestedElseIfExpression = branches.lastOrNull()?.nestedElseIfOrNull() ?: return true
return nestedElseIfExpression.isDeeplyProperlyExhaustive()
}
/**
* Converts the branches to [IrBranch]es.
*
* If [flattenElse] is `true` and the else branch contains another [FirWhenExpression] that's built from an `if`,
* its branches will be added directly to the [result] list instead.
*
* TODO this shouldn't be required anymore once KT-65997 is fixed.
*/
private fun FirWhenExpression.convertWhenBranchesTo(
result: MutableList<IrBranch>,
whenExpressionType: ConeKotlinType,
flattenElse: Boolean,
): MutableList<IrBranch> {
for (branch in branches) {
if (flattenElse) {
val elseIfExpression = branch.nestedElseIfOrNull()
if (elseIfExpression != null) {
elseIfExpression.convertWhenBranchesTo(result, whenExpressionType, flattenElse = true)
break
}
}
result.add(branch.toIrWhenBranch(whenExpressionType))
}
return result
}
private fun FirWhenBranch.nestedElseIfOrNull(): FirWhenExpression? {
if (condition is FirElseIfTrueCondition) {
val elseWhenExpression = (result as? FirSingleExpressionBlock)?.statement as? FirWhenExpression
if (elseWhenExpression != null && elseWhenExpression.source?.elementType == KtNodeTypes.IF) {
return elseWhenExpression
}
}
return null
}
private fun generateWhen(
startOffset: Int,
endOffset: Int,
@@ -1335,42 +1335,28 @@ class LightTreeRawFirExpressionBuilder(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitIfExpression
*/
private fun convertIfExpression(ifExpression: LighterASTNode): FirExpression {
var components = parseIfExpression(ifExpression)
return buildWhenExpression {
source = ifExpression.toFirSourceElement()
whenBranches@ while (true) {
with(components) {
val trueBranch = convertLoopBody(thenBlock)
branches += buildWhenBranch {
source = firCondition?.source
condition = firCondition ?: buildErrorExpression(
null,
ConeSyntaxDiagnostic("If statement should have condition")
)
result = trueBranch
}
with(parseIfExpression(ifExpression)) {
val trueBranch = convertLoopBody(thenBlock)
branches += buildWhenBranch {
source = firCondition?.source
condition = firCondition ?: buildErrorExpression(
null,
ConeSyntaxDiagnostic("If statement should have condition")
)
result = trueBranch
}
if (components.elseBlock == null) break@whenBranches
var cascadeIf = false
components.elseBlock?.forEachChildren {
if (it.tokenType == IF) {
cascadeIf = true
components = parseIfExpression(it)
}
}
if (!cascadeIf) {
with(components) {
val elseBranch = convertLoopOrIfBody(elseBlock)
if (elseBranch != null) {
branches += buildWhenBranch {
source = elseBlock?.toFirSourceElement()
condition = buildElseIfTrueCondition()
result = elseBranch
}
if (elseBlock != null) {
val elseBranch = convertLoopOrIfBody(elseBlock)
if (elseBranch != null) {
branches += buildWhenBranch {
source = elseBlock.toFirSourceElement()
condition = buildElseIfTrueCondition()
result = elseBranch
}
}
break@whenBranches
}
}
usedAsExpression = ifExpression.usedAsExpression
@@ -2555,26 +2555,18 @@ open class PsiRawFirBuilder(
return buildWhenExpression {
source = expression.toFirSourceElement()
var ktLastIf: KtIfExpression = expression
whenBranches@ while (true) {
val ktCondition = ktLastIf.condition
branches += buildWhenBranch {
source = ktCondition?.toFirSourceElement(KtFakeSourceElementKind.WhenCondition)
condition = ktCondition.toFirExpression("If statement should have condition")
result = ktLastIf.then.toFirBlock()
}
val ktCondition = expression.condition
branches += buildWhenBranch {
source = ktCondition?.toFirSourceElement(KtFakeSourceElementKind.WhenCondition)
condition = ktCondition.toFirExpression("If statement should have condition")
result = expression.then.toFirBlock()
}
when (val ktElse = ktLastIf.`else`) {
null -> break@whenBranches
is KtIfExpression -> ktLastIf = ktElse
else -> {
branches += buildWhenBranch {
source = ktLastIf.elseKeyword?.toKtPsiSourceElement()
condition = buildElseIfTrueCondition()
result = ktLastIf.`else`.toFirBlock()
}
break@whenBranches
}
if (expression.`else` != null) {
branches += buildWhenBranch {
source = expression.elseKeyword?.toKtPsiSourceElement()
condition = buildElseIfTrueCondition()
result = expression.`else`.toFirBlock()
}
}
@@ -4,17 +4,22 @@ FILE: cascadeIf.kt
first# -> {
^foo IntegerLiteral(4)
}
second# -> {
lval x: <implicit> = IntegerLiteral(3)
^foo x#.plus#(IntegerLiteral(2))
}
else -> {
when () {
third# -> {
^foo IntegerLiteral(0)
second# -> {
lval x: <implicit> = IntegerLiteral(3)
^foo x#.plus#(IntegerLiteral(2))
}
else -> {
^foo IntegerLiteral(-1)
when () {
third# -> {
^foo IntegerLiteral(0)
}
else -> {
^foo IntegerLiteral(-1)
}
}
}
}
@@ -3,7 +3,15 @@ interface Promise<T>
fun <T> materializePromise(): Promise<T> = TODO()
fun foo(x: Int, p1: Promise<Any?>, p2: Promise<Nothing?>): Promise<*> {
fun foo0(x: Int, p2: Promise<Nothing?>): Promise<*> {
return if (x == 3) {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>materializePromise<!>()
} else {
p2
}
}
fun foo1(x: Int, p1: Promise<Any?>, p2: Promise<Nothing?>): Promise<*> {
return if (x == 0) {
p1
} else {
@@ -15,10 +23,12 @@ fun foo(x: Int, p1: Promise<Any?>, p2: Promise<Nothing?>): Promise<*> {
}
}
fun foo2(x: Int, p2: Promise<Nothing?>): Promise<*> {
return if (x == 3) {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>materializePromise<!>()
fun foo2(x: Int, p1: Promise<Any?>): Promise<*> {
return if (x == 0) {
p1
} else if (x == 2) {
materializePromise()
} else {
p2
p1
}
}
}
@@ -1,31 +0,0 @@
// !DIAGNOSTICS: -IMPLICIT_CAST_TO_ANY -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_PARAMETER -UNUSED_EXPRESSION
// SKIP_TXT
/*
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
*
* SPEC VERSION: 0.1-296
* MAIN LINK: control--and-data-flow-analysis, control-flow-graph, expressions-1, conditional-expressions -> paragraph 1 -> sentence 1
* NUMBER: 2
* DESCRIPTION: check if-expressions must have both branches.
*/
// TESTCASE NUMBER: 1
fun case1() {
val b = true
val c = true
val a = <!INVALID_IF_AS_EXPRESSION!>if<!> (b) {
"first true"
} else if (c) {
"else if true"
}
}
// TESTCASE NUMBER: 2
fun case2() {
var b = true
val c = true
val a = <!INVALID_IF_AS_EXPRESSION!>if<!> (b) 1 else if (c) 2 else ;
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -IMPLICIT_CAST_TO_ANY -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_PARAMETER -UNUSED_EXPRESSION
// SKIP_TXT
@@ -36,7 +36,7 @@ fun case4() {
val x2 = <!INVALID_IF_AS_EXPRESSION!>if<!> (TODO()) true
val x0 = <!INVALID_IF_AS_EXPRESSION!>if<!> (false) true else if (throw Exception()) ;
val x0 = if (false) true else <!INVALID_IF_AS_EXPRESSION!>if<!> (throw Exception()) ;
}
@@ -43,5 +43,5 @@ fun case4(nothing: Nothing) {
// TESTCASE NUMBER: 5
fun case5(nothing: Nothing) {
val x = <!INVALID_IF_AS_EXPRESSION!>if<!> (false) else if (nothing) { "foo"} else ;
val x = <!INVALID_IF_AS_EXPRESSION!>if<!> (false) else <!INVALID_IF_AS_EXPRESSION!>if<!> (nothing) { "foo"} else ;
}