Fir2Ir: generate coercion to Unit for when branches if needed

Before this change, it could happen that `when` of type Unit has a
branch whose type is not Unit. This can lead to problems in IR
lowerings, for example PolymorphicSignatureLowering which is very
reliant on the correct types of expressions and placement of coercions
to Unit (KT-59218).
This commit is contained in:
Alexander Udalov
2023-06-28 15:12:10 +02:00
committed by Space Team
parent 5513740659
commit 79fa2b6db0
3 changed files with 10 additions and 11 deletions
@@ -1092,8 +1092,12 @@ class Fir2IrVisitor(
if (whenExpression.branches.isEmpty()) { if (whenExpression.branches.isEmpty()) {
return@convertWithOffsets IrBlockImpl(startOffset, endOffset, irBuiltIns.unitType, origin) return@convertWithOffsets IrBlockImpl(startOffset, endOffset, irBuiltIns.unitType, origin)
} }
val whenExpressionType =
if (whenExpression.isProperlyExhaustive && whenExpression.branches.none {
it.condition is FirElseIfTrueCondition && it.result.statements.isEmpty()
}) whenExpression.typeRef else session.builtinTypes.unitType
val irBranches = whenExpression.branches.mapTo(mutableListOf()) { branch -> val irBranches = whenExpression.branches.mapTo(mutableListOf()) { branch ->
branch.toIrWhenBranch(whenExpression.typeRef) branch.toIrWhenBranch(whenExpressionType)
} }
if (whenExpression.isProperlyExhaustive && whenExpression.branches.none { it.condition is FirElseIfTrueCondition }) { if (whenExpression.isProperlyExhaustive && whenExpression.branches.none { it.condition is FirElseIfTrueCondition }) {
val irResult = IrCallImpl( val irResult = IrCallImpl(
@@ -1106,14 +1110,7 @@ class Fir2IrVisitor(
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true), irResult IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true), irResult
) )
} }
generateWhen( generateWhen(startOffset, endOffset, origin, subjectVariable, irBranches, whenExpressionType.toIrType())
startOffset, endOffset, origin,
subjectVariable, irBranches,
if (whenExpression.isProperlyExhaustive && whenExpression.branches.none {
it.condition is FirElseIfTrueCondition && it.result.statements.isEmpty()
}
) whenExpression.typeRef.toIrType() else irBuiltIns.unitType
)
} }
}.also { }.also {
whenExpression.accept(implicitCastInserter, it) whenExpression.accept(implicitCastInserter, it)
@@ -47,7 +47,8 @@ FILE fqName:<root> fileName:/ifElseIf.kt
WHEN type=kotlin.Unit origin=IF WHEN type=kotlin.Unit origin=IF
BRANCH BRANCH
if: GET_VAR 'flag: kotlin.Boolean declared in <root>.testEmptyBranches2' type=kotlin.Boolean origin=null if: GET_VAR 'flag: kotlin.Boolean declared in <root>.testEmptyBranches2' type=kotlin.Boolean origin=null
then: CONST Boolean type=kotlin.Boolean value=true then: TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
CONST Boolean type=kotlin.Boolean value=true
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: BLOCK type=kotlin.Unit origin=null then: BLOCK type=kotlin.Unit origin=null
@@ -24,7 +24,7 @@ fun testEmptyBranches2(flag: Boolean) {
else -> true else -> true
} /*~> Unit */ } /*~> Unit */
when { when {
flag -> true flag -> true /*~> Unit */
else -> { // BLOCK else -> { // BLOCK
} }
} }
@@ -37,3 +37,4 @@ fun testEmptyBranches3(flag: Boolean) {
else -> true else -> true
} /*~> Unit */ } /*~> Unit */
} }