From 38fa0122e81ec6b12d73792de5beec8af0e112db Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 8 Aug 2019 14:02:01 +0300 Subject: [PATCH] [FIR] Add synthetic else branch to `when` if it's missing This change is needed for correct work of data flow, because for non-exhaustive when there is a else branch in terms of control flow graph. This change leads to some errors when when is actually exhaustive, but we still add else branch. Those errors will be gone when exhaustive checker will be introduced --- .../kotlin/fir/builder/RawFirBuilder.kt | 5 +++++ .../recursiveCallOnWhenWithSealedClass.txt | 2 ++ .../irText/expressions/whenCoercedToUnit.fir.txt | 4 ++-- .../ir/irText/regressions/kt24114.fir.txt | 16 ++++++++-------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index c084ef97572..a1c34ea8746 100644 --- a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -943,6 +943,7 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder if (hasSubject) { subject.bind(this) } + var thereIsElseBranch = false for (entry in expression.entries) { val branch = entry.expression.toFirBlock() branches += if (!entry.isElse) { @@ -960,9 +961,13 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder FirWhenBranchImpl(entry, firCondition, branch) } } else { + thereIsElseBranch = true FirWhenBranchImpl(entry, FirElseIfTrueCondition(null), branch) } } + if (!thereIsElseBranch) { + branches += FirWhenBranchImpl(null, FirElseIfTrueCondition(null), FirEmptyExpressionBlock()) + } } } diff --git a/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt b/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt index acb722ad5fb..6a50d7a754c 100644 --- a/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt +++ b/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt @@ -35,6 +35,8 @@ FILE: recursiveCallOnWhenWithSealedClass.kt ($subj$ is R|Maybe.Yeah|) -> { # } + else -> { + } } } diff --git a/compiler/testData/ir/irText/expressions/whenCoercedToUnit.fir.txt b/compiler/testData/ir/irText/expressions/whenCoercedToUnit.fir.txt index a1cba47a581..da87de4dc9e 100644 --- a/compiler/testData/ir/irText/expressions/whenCoercedToUnit.fir.txt +++ b/compiler/testData/ir/irText/expressions/whenCoercedToUnit.fir.txt @@ -2,9 +2,9 @@ FILE fqName: fileName:/whenCoercedToUnit.kt FUN name:foo visibility:public modality:FINAL <> (x:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:x index:0 type:kotlin.Int BLOCK_BODY - BLOCK type=kotlin.Int origin=WHEN + BLOCK type=kotlin.Unit origin=WHEN VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Int [val] - WHEN type=kotlin.Int origin=WHEN + WHEN type=kotlin.Unit origin=WHEN BRANCH if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ arg0: GET_VAR 'val tmp0_subject: kotlin.Int [val] declared in .foo' type=kotlin.Int origin=null diff --git a/compiler/testData/ir/irText/regressions/kt24114.fir.txt b/compiler/testData/ir/irText/regressions/kt24114.fir.txt index 34939b41d38..dc4e9d4ef00 100644 --- a/compiler/testData/ir/irText/regressions/kt24114.fir.txt +++ b/compiler/testData/ir/irText/regressions/kt24114.fir.txt @@ -11,16 +11,16 @@ FILE fqName: fileName:/kt24114.kt BLOCK_BODY WHILE label=null origin=WHILE_LOOP condition: CONST Boolean type=kotlin.Boolean value=true - body: BLOCK type=kotlin.Int origin=WHEN + body: BLOCK type=kotlin.Unit origin=WHEN VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Int [val] - WHEN type=kotlin.Int origin=WHEN + WHEN type=kotlin.Unit origin=WHEN BRANCH if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ arg0: GET_VAR 'val tmp0_subject: kotlin.Int [val] declared in .test1' type=kotlin.Int origin=null arg1: CONST Int type=kotlin.Int value=1 - then: BLOCK type=kotlin.Nothing origin=WHEN + then: BLOCK type=kotlin.Unit origin=WHEN VAR IR_TEMPORARY_VARIABLE name:tmp1_subject type:kotlin.Int [val] - WHEN type=kotlin.Nothing origin=WHEN + WHEN type=kotlin.Unit origin=WHEN BRANCH if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ arg0: GET_VAR 'val tmp1_subject: kotlin.Int [val] declared in .test1' type=kotlin.Int origin=null @@ -35,16 +35,16 @@ FILE fqName: fileName:/kt24114.kt BLOCK_BODY WHILE label=null origin=WHILE_LOOP condition: CONST Boolean type=kotlin.Boolean value=true - body: BLOCK type=kotlin.Int origin=WHEN + body: BLOCK type=kotlin.Unit origin=WHEN VAR IR_TEMPORARY_VARIABLE name:tmp2_subject type:kotlin.Int [val] - WHEN type=kotlin.Int origin=WHEN + WHEN type=kotlin.Unit origin=WHEN BRANCH if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ arg0: GET_VAR 'val tmp2_subject: kotlin.Int [val] declared in .test2' type=kotlin.Int origin=null arg1: CONST Int type=kotlin.Int value=1 - then: BLOCK type=kotlin.Nothing origin=WHEN + then: BLOCK type=kotlin.Unit origin=WHEN VAR IR_TEMPORARY_VARIABLE name:tmp3_subject type:kotlin.Int [val] - WHEN type=kotlin.Nothing origin=WHEN + WHEN type=kotlin.Unit origin=WHEN BRANCH if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ arg0: GET_VAR 'val tmp3_subject: kotlin.Int [val] declared in .test2' type=kotlin.Int origin=null