[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
This commit is contained in:
Dmitriy Novozhilov
2019-08-08 14:02:01 +03:00
parent e904e638e9
commit 38fa0122e8
4 changed files with 17 additions and 10 deletions
@@ -943,6 +943,7 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder
if (hasSubject) { if (hasSubject) {
subject.bind(this) subject.bind(this)
} }
var thereIsElseBranch = false
for (entry in expression.entries) { for (entry in expression.entries) {
val branch = entry.expression.toFirBlock() val branch = entry.expression.toFirBlock()
branches += if (!entry.isElse) { branches += if (!entry.isElse) {
@@ -960,9 +961,13 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder
FirWhenBranchImpl(entry, firCondition, branch) FirWhenBranchImpl(entry, firCondition, branch)
} }
} else { } else {
thereIsElseBranch = true
FirWhenBranchImpl(entry, FirElseIfTrueCondition(null), branch) FirWhenBranchImpl(entry, FirElseIfTrueCondition(null), branch)
} }
} }
if (!thereIsElseBranch) {
branches += FirWhenBranchImpl(null, FirElseIfTrueCondition(null), FirEmptyExpressionBlock())
}
} }
} }
@@ -35,6 +35,8 @@ FILE: recursiveCallOnWhenWithSealedClass.kt
($subj$ is R|Maybe.Yeah|) -> { ($subj$ is R|Maybe.Yeah|) -> {
<Unresolved name: meat># <Unresolved name: meat>#
} }
else -> {
}
} }
} }
@@ -2,9 +2,9 @@ FILE fqName:<root> fileName:/whenCoercedToUnit.kt
FUN name:foo visibility:public modality:FINAL <> (x:kotlin.Int) returnType:kotlin.Unit FUN name:foo visibility:public modality:FINAL <> (x:kotlin.Int) returnType:kotlin.Unit
VALUE_PARAMETER name:x index:0 type:kotlin.Int VALUE_PARAMETER name:x index:0 type:kotlin.Int
BLOCK_BODY 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] VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Int [val]
WHEN type=kotlin.Int origin=WHEN WHEN type=kotlin.Unit origin=WHEN
BRANCH 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 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 <root>.foo' type=kotlin.Int origin=null arg0: GET_VAR 'val tmp0_subject: kotlin.Int [val] declared in <root>.foo' type=kotlin.Int origin=null
+8 -8
View File
@@ -11,16 +11,16 @@ FILE fqName:<root> fileName:/kt24114.kt
BLOCK_BODY BLOCK_BODY
WHILE label=null origin=WHILE_LOOP WHILE label=null origin=WHILE_LOOP
condition: CONST Boolean type=kotlin.Boolean value=true 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] VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Int [val]
WHEN type=kotlin.Int origin=WHEN WHEN type=kotlin.Unit origin=WHEN
BRANCH 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 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 <root>.test1' type=kotlin.Int origin=null arg0: GET_VAR 'val tmp0_subject: kotlin.Int [val] declared in <root>.test1' type=kotlin.Int origin=null
arg1: CONST Int type=kotlin.Int value=1 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] VAR IR_TEMPORARY_VARIABLE name:tmp1_subject type:kotlin.Int [val]
WHEN type=kotlin.Nothing origin=WHEN WHEN type=kotlin.Unit origin=WHEN
BRANCH 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 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 <root>.test1' type=kotlin.Int origin=null arg0: GET_VAR 'val tmp1_subject: kotlin.Int [val] declared in <root>.test1' type=kotlin.Int origin=null
@@ -35,16 +35,16 @@ FILE fqName:<root> fileName:/kt24114.kt
BLOCK_BODY BLOCK_BODY
WHILE label=null origin=WHILE_LOOP WHILE label=null origin=WHILE_LOOP
condition: CONST Boolean type=kotlin.Boolean value=true 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] VAR IR_TEMPORARY_VARIABLE name:tmp2_subject type:kotlin.Int [val]
WHEN type=kotlin.Int origin=WHEN WHEN type=kotlin.Unit origin=WHEN
BRANCH 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 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 <root>.test2' type=kotlin.Int origin=null arg0: GET_VAR 'val tmp2_subject: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
arg1: CONST Int type=kotlin.Int value=1 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] VAR IR_TEMPORARY_VARIABLE name:tmp3_subject type:kotlin.Int [val]
WHEN type=kotlin.Nothing origin=WHEN WHEN type=kotlin.Unit origin=WHEN
BRANCH 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 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 <root>.test2' type=kotlin.Int origin=null arg0: GET_VAR 'val tmp3_subject: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null