FIR2IR: never generate empty when #KT-55459 Fixed

In details, this commit changes the following:
- it converts FIR when without branches to empty IR block without when
- it doesn't drop empty else branches in when anymore
This commit is contained in:
Mikhail Glukhikh
2023-01-24 16:31:14 +01:00
committed by Space Team
parent b026678a34
commit ae4b8be16b
11 changed files with 85 additions and 9 deletions
@@ -1013,12 +1013,11 @@ class Fir2IrVisitor(
}
return conversionScope.withWhenSubject(subjectVariable) {
whenExpression.convertWithOffsets { startOffset, endOffset ->
// If the constant true branch has empty body, it won't be converted. Thus, the entire `when` expression is effectively _not_
// exhaustive anymore. In that case, coerce the return type of `when` expression to Unit as per the backend expectation.
val irBranches = whenExpression.branches.mapNotNullTo(mutableListOf()) { branch ->
branch.takeIf {
it.condition !is FirElseIfTrueCondition || it.result.statements.isNotEmpty()
}?.toIrWhenBranch(whenExpression.typeRef)
if (whenExpression.branches.isEmpty()) {
return@convertWithOffsets IrBlockImpl(startOffset, endOffset, irBuiltIns.unitType, origin)
}
val irBranches = whenExpression.branches.mapTo(mutableListOf()) { branch ->
branch.toIrWhenBranch(whenExpression.typeRef)
}
if (whenExpression.isProperlyExhaustive && whenExpression.branches.none { it.condition is FirElseIfTrueCondition }) {
val irResult = IrCallImpl(
@@ -2600,6 +2600,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
runTest("compiler/testData/ir/irText/firProblems/deprecated.kt");
}
@Test
@TestMetadata("emptyWhen.kt")
public void testEmptyWhen() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/emptyWhen.kt");
}
@Test
@TestMetadata("Fir2IrClassifierStorage.kt")
public void testFir2IrClassifierStorage() throws Exception {
@@ -2600,6 +2600,12 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex
runTest("compiler/testData/ir/irText/firProblems/deprecated.kt");
}
@Test
@TestMetadata("emptyWhen.kt")
public void testEmptyWhen() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/emptyWhen.kt");
}
@Test
@TestMetadata("Fir2IrClassifierStorage.kt")
public void testFir2IrClassifierStorage() throws Exception {
-3
View File
@@ -1,6 +1,3 @@
// KT-55459
// IGNORE_BACKEND_K2: NATIVE
enum class A { X1, X2 }
fun box(): String {
@@ -48,6 +48,9 @@ FILE fqName:<root> fileName:/ifElseIf.kt
BRANCH
if: GET_VAR 'flag: kotlin.Boolean declared in <root>.testEmptyBranches2' type=kotlin.Boolean origin=null
then: CONST Boolean type=kotlin.Boolean value=true
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: BLOCK type=kotlin.Unit origin=null
FUN name:testEmptyBranches3 visibility:public modality:FINAL <> (flag:kotlin.Boolean) returnType:kotlin.Unit
VALUE_PARAMETER name:flag index:0 type:kotlin.Boolean
BLOCK_BODY
@@ -25,6 +25,8 @@ fun testEmptyBranches2(flag: Boolean) {
} /*~> Unit */
when {
flag -> true
else -> { // BLOCK
}
}
}
@@ -0,0 +1,21 @@
FILE fqName:<root> fileName:/emptyWhen.kt
FUN name:foo visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
BLOCK type=kotlin.Unit origin=WHEN
VAR name:x type:kotlin.Int [val]
CONST Int type=kotlin.Int value=0
BLOCK type=kotlin.Unit origin=WHEN
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
GET_VAR 'val x: kotlin.Int [val] declared in <root>.foo' type=kotlin.Int origin=null
WHEN type=kotlin.Unit origin=WHEN
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: BLOCK type=kotlin.Unit origin=null
VAR name:z type:kotlin.Unit [val]
BLOCK type=kotlin.Unit origin=WHEN
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
GET_VAR 'val x: kotlin.Int [val] declared in <root>.foo' type=kotlin.Int origin=null
WHEN type=kotlin.Unit origin=WHEN
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: BLOCK type=kotlin.Unit origin=null
+11
View File
@@ -0,0 +1,11 @@
// FIR_IDENTICAL
fun foo() {
when {}
val x = 0
when (x) {
else -> {}
}
val z = when (x) {
else -> {}
}
}
@@ -0,0 +1,20 @@
fun foo() {
{ // BLOCK
}
val x: Int = 0
{ // BLOCK
val tmp0_subject: Int = x
when {
else -> { // BLOCK
}
}
}
val z: Unit = { // BLOCK
val tmp1_subject: Int = x
when {
else -> { // BLOCK
}
}
}
}
@@ -2600,6 +2600,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest {
runTest("compiler/testData/ir/irText/firProblems/deprecated.kt");
}
@Test
@TestMetadata("emptyWhen.kt")
public void testEmptyWhen() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/emptyWhen.kt");
}
@Test
@TestMetadata("Fir2IrClassifierStorage.kt")
public void testFir2IrClassifierStorage() throws Exception {
@@ -1905,6 +1905,11 @@ public class KlibTextTestCaseGenerated extends AbstractKlibTextTestCase {
runTest("compiler/testData/ir/irText/firProblems/deprecated.kt");
}
@TestMetadata("emptyWhen.kt")
public void testEmptyWhen() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/emptyWhen.kt");
}
@TestMetadata("Fir2IrClassifierStorage.kt")
public void testFir2IrClassifierStorage() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/Fir2IrClassifierStorage.kt");