psi2ir: keep the type of when when possible
Ideally, the type of `IrWhen` should be provided by type inference for a consistent behavior. `USED_AS_EXPRESSION` from CFG isn't always consistent with type inference, unfortunately. The behavior is now aligned with `if`. The type of `when` is kept when it *can* be an expression, instead of whether it is used or not.
This commit is contained in:
committed by
max-kammerer
parent
cd651be461
commit
1b4d26e490
+5
@@ -1267,6 +1267,11 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
|
|||||||
runTest("compiler/testData/ir/irText/expressions/whenReturn.kt");
|
runTest("compiler/testData/ir/irText/expressions/whenReturn.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whenUnusedExpression.kt")
|
||||||
|
public void testWhenUnusedExpression() throws Exception {
|
||||||
|
runTest("compiler/testData/ir/irText/expressions/whenUnusedExpression.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("whenWithSubjectVariable.kt")
|
@TestMetadata("whenWithSubjectVariable.kt")
|
||||||
public void testWhenWithSubjectVariable() throws Exception {
|
public void testWhenWithSubjectVariable() throws Exception {
|
||||||
runTest("compiler/testData/ir/irText/expressions/whenWithSubjectVariable.kt");
|
runTest("compiler/testData/ir/irText/expressions/whenWithSubjectVariable.kt");
|
||||||
|
|||||||
+2
-4
@@ -104,11 +104,9 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
|
|||||||
|
|
||||||
val inferredType = getInferredTypeWithImplicitCastsOrFail(expression)
|
val inferredType = getInferredTypeWithImplicitCastsOrFail(expression)
|
||||||
|
|
||||||
// TODO relies on ControlFlowInformationProvider, get rid of it
|
|
||||||
val isUsedAsExpression = get(BindingContext.USED_AS_EXPRESSION, expression) ?: false
|
|
||||||
|
|
||||||
val resultType = when {
|
val resultType = when {
|
||||||
isUsedAsExpression -> inferredType.toIrType()
|
// Non-exhaustive when can only be used as statement.
|
||||||
|
expression.isExhaustiveWhen() -> inferredType.toIrType()
|
||||||
KotlinBuiltIns.isNothing(inferredType) -> inferredType.toIrType()
|
KotlinBuiltIns.isNothing(inferredType) -> inferredType.toIrType()
|
||||||
else -> context.irBuiltIns.unitType
|
else -> context.irBuiltIns.unitType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
// Even before any IR lowerings, the type of `when` is determined to be
|
|
||||||
// Unit even though the outer `if` still returns `Int?`. This results
|
|
||||||
// in a ClassCastException when that Unit is converted into a Number.
|
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun test(
|
fun test(
|
||||||
b: Boolean,
|
b: Boolean,
|
||||||
i: Int
|
i: Int
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
FILE fqName:<root> fileName:/whenUnusedExpression.kt
|
||||||
|
FUN name:test visibility:public modality:FINAL <> (b:kotlin.Boolean, i:kotlin.Int) returnType:kotlin.Unit
|
||||||
|
VALUE_PARAMETER name:b index:0 type:kotlin.Boolean
|
||||||
|
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
WHEN type=kotlin.Unit origin=IF
|
||||||
|
BRANCH
|
||||||
|
if: GET_VAR 'b: kotlin.Boolean declared in <root>.test' type=kotlin.Boolean origin=null
|
||||||
|
then: BLOCK type=kotlin.Unit origin=WHEN
|
||||||
|
VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Int [val]
|
||||||
|
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 <root>.test' type=kotlin.Int origin=null
|
||||||
|
arg1: CONST Int type=kotlin.Unit value=0
|
||||||
|
then: CONST Int type=kotlin.Unit value=1
|
||||||
|
BRANCH
|
||||||
|
if: CONST Boolean type=kotlin.Boolean value=true
|
||||||
|
then: CONST Null type=kotlin.Nothing? value=null
|
||||||
|
BRANCH
|
||||||
|
if: CONST Boolean type=kotlin.Boolean value=true
|
||||||
|
then: CONST Null type=kotlin.Nothing? value=null
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test(b: Boolean, i: Int) {
|
||||||
|
if (b) {
|
||||||
|
when (i) {
|
||||||
|
0 -> 1
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
FILE fqName:<root> fileName:/whenUnusedExpression.kt
|
||||||
|
FUN name:test visibility:public modality:FINAL <> (b:kotlin.Boolean, i:kotlin.Int) returnType:kotlin.Unit
|
||||||
|
VALUE_PARAMETER name:b index:0 type:kotlin.Boolean
|
||||||
|
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||||
|
WHEN type=kotlin.Int? origin=IF
|
||||||
|
BRANCH
|
||||||
|
if: GET_VAR 'b: kotlin.Boolean declared in <root>.test' type=kotlin.Boolean origin=null
|
||||||
|
then: BLOCK type=kotlin.Int? origin=null
|
||||||
|
BLOCK type=kotlin.Int? origin=WHEN
|
||||||
|
VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Int [val]
|
||||||
|
GET_VAR 'i: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
|
||||||
|
WHEN type=kotlin.Int? 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 <root>.test' type=kotlin.Int origin=null
|
||||||
|
arg1: CONST Int type=kotlin.Int value=0
|
||||||
|
then: CONST Int type=kotlin.Int value=1
|
||||||
|
BRANCH
|
||||||
|
if: CONST Boolean type=kotlin.Boolean value=true
|
||||||
|
then: CONST Null type=kotlin.Nothing? value=null
|
||||||
|
BRANCH
|
||||||
|
if: CONST Boolean type=kotlin.Boolean value=true
|
||||||
|
then: CONST Null type=kotlin.Nothing? value=null
|
||||||
@@ -1267,6 +1267,11 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
runTest("compiler/testData/ir/irText/expressions/whenReturn.kt");
|
runTest("compiler/testData/ir/irText/expressions/whenReturn.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whenUnusedExpression.kt")
|
||||||
|
public void testWhenUnusedExpression() throws Exception {
|
||||||
|
runTest("compiler/testData/ir/irText/expressions/whenUnusedExpression.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("whenWithSubjectVariable.kt")
|
@TestMetadata("whenWithSubjectVariable.kt")
|
||||||
public void testWhenWithSubjectVariable() throws Exception {
|
public void testWhenWithSubjectVariable() throws Exception {
|
||||||
runTest("compiler/testData/ir/irText/expressions/whenWithSubjectVariable.kt");
|
runTest("compiler/testData/ir/irText/expressions/whenWithSubjectVariable.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user