From ae4b8be16b1af5499df10bd576a899780403358a Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 24 Jan 2023 16:31:14 +0100 Subject: [PATCH] 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 --- .../kotlin/fir/backend/Fir2IrVisitor.kt | 11 +++++----- .../runners/ir/Fir2IrTextTestGenerated.java | 6 ++++++ .../ir/LightTreeFir2IrTextTestGenerated.java | 6 ++++++ .../testData/codegen/box/when/emptyWhen.kt | 3 --- .../ir/irText/expressions/ifElseIf.fir.ir.txt | 3 +++ .../ir/irText/expressions/ifElseIf.fir.kt.txt | 2 ++ .../ir/irText/firProblems/emptyWhen.ir.txt | 21 +++++++++++++++++++ .../ir/irText/firProblems/emptyWhen.kt | 11 ++++++++++ .../ir/irText/firProblems/emptyWhen.kt.txt | 20 ++++++++++++++++++ .../test/runners/ir/IrTextTestGenerated.java | 6 ++++++ .../klib/KlibTextTestCaseGenerated.java | 5 +++++ 11 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/ir/irText/firProblems/emptyWhen.ir.txt create mode 100644 compiler/testData/ir/irText/firProblems/emptyWhen.kt create mode 100644 compiler/testData/ir/irText/firProblems/emptyWhen.kt.txt 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 c5770fe084f..a5992cd844f 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 @@ -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( diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java index a3d602ea0db..f4a27d405fc 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java @@ -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 { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java index 7a9a32da9c9..98d262180ab 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java @@ -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 { diff --git a/compiler/testData/codegen/box/when/emptyWhen.kt b/compiler/testData/codegen/box/when/emptyWhen.kt index dff7c796905..58fbad659db 100644 --- a/compiler/testData/codegen/box/when/emptyWhen.kt +++ b/compiler/testData/codegen/box/when/emptyWhen.kt @@ -1,6 +1,3 @@ -// KT-55459 -// IGNORE_BACKEND_K2: NATIVE - enum class A { X1, X2 } fun box(): String { diff --git a/compiler/testData/ir/irText/expressions/ifElseIf.fir.ir.txt b/compiler/testData/ir/irText/expressions/ifElseIf.fir.ir.txt index c76443efa3d..8f6ca19d70e 100644 --- a/compiler/testData/ir/irText/expressions/ifElseIf.fir.ir.txt +++ b/compiler/testData/ir/irText/expressions/ifElseIf.fir.ir.txt @@ -48,6 +48,9 @@ FILE fqName: fileName:/ifElseIf.kt BRANCH if: GET_VAR 'flag: kotlin.Boolean declared in .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 diff --git a/compiler/testData/ir/irText/expressions/ifElseIf.fir.kt.txt b/compiler/testData/ir/irText/expressions/ifElseIf.fir.kt.txt index f6cd82fabe6..4298ff4dd63 100644 --- a/compiler/testData/ir/irText/expressions/ifElseIf.fir.kt.txt +++ b/compiler/testData/ir/irText/expressions/ifElseIf.fir.kt.txt @@ -25,6 +25,8 @@ fun testEmptyBranches2(flag: Boolean) { } /*~> Unit */ when { flag -> true + else -> { // BLOCK + } } } diff --git a/compiler/testData/ir/irText/firProblems/emptyWhen.ir.txt b/compiler/testData/ir/irText/firProblems/emptyWhen.ir.txt new file mode 100644 index 00000000000..25a92b52461 --- /dev/null +++ b/compiler/testData/ir/irText/firProblems/emptyWhen.ir.txt @@ -0,0 +1,21 @@ +FILE fqName: 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 .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 .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 diff --git a/compiler/testData/ir/irText/firProblems/emptyWhen.kt b/compiler/testData/ir/irText/firProblems/emptyWhen.kt new file mode 100644 index 00000000000..9a90e215ab7 --- /dev/null +++ b/compiler/testData/ir/irText/firProblems/emptyWhen.kt @@ -0,0 +1,11 @@ +// FIR_IDENTICAL +fun foo() { + when {} + val x = 0 + when (x) { + else -> {} + } + val z = when (x) { + else -> {} + } +} diff --git a/compiler/testData/ir/irText/firProblems/emptyWhen.kt.txt b/compiler/testData/ir/irText/firProblems/emptyWhen.kt.txt new file mode 100644 index 00000000000..3c2f2e9d099 --- /dev/null +++ b/compiler/testData/ir/irText/firProblems/emptyWhen.kt.txt @@ -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 + } + } + } +} + diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java index 1327156ff56..d77d24c74d8 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java @@ -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 { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java index d4eb370323d..652f7594997 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java @@ -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");