FIR2IR insert implicit cast on elvis RHS

This commit is contained in:
Dmitry Petrov
2021-11-24 15:15:47 +03:00
committed by Space
parent badfade2fd
commit 91b1814b02
9 changed files with 125 additions and 9 deletions
@@ -292,14 +292,22 @@ class Fir2IrVisitor(
)
if (initializer != null) {
irVariable.initializer =
with(implicitCastInserter) {
convertToIrExpression(initializer).cast(initializer, initializer.typeRef, variable.returnTypeRef)
}
convertToIrExpression(initializer)
.insertImplicitCast(initializer, initializer.typeRef, variable.returnTypeRef)
}
annotationGenerator.generate(irVariable, variable)
return irVariable
}
private fun IrExpression.insertImplicitCast(
baseExpression: FirExpression,
valueType: FirTypeRef,
expectedType: FirTypeRef
) =
with(implicitCastInserter) {
this@insertImplicitCast.cast(baseExpression, valueType, expectedType)
}
override fun visitProperty(property: FirProperty, data: Any?): IrElement {
if (property.isLocal) return visitLocalVariable(property)
val irProperty = declarationStorage.getCachedIrProperty(property)!!
@@ -707,13 +715,15 @@ class Fir2IrVisitor(
val notNullType = originalType.withNullability(ConeNullability.NOT_NULL, session.typeContext)
val irBranches = listOf(
IrBranchImpl(
startOffset, endOffset, primitiveOp2(
startOffset, endOffset,
primitiveOp2(
startOffset, endOffset, irBuiltIns.eqeqSymbol,
irBuiltIns.booleanType, IrStatementOrigin.EQEQ,
irGetLhsValue(),
IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType)
),
convertToIrExpression(elvisExpression.rhs)
.insertImplicitCast(elvisExpression, elvisExpression.rhs.typeRef, elvisExpression.typeRef)
),
IrElseBranchImpl(
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true),
@@ -815,9 +825,7 @@ class Fir2IrVisitor(
private fun FirWhenBranch.toIrWhenBranch(whenExpressionType: FirTypeRef): IrBranch {
return convertWithOffsets { startOffset, endOffset ->
val condition = condition
val irResult = with(implicitCastInserter) {
convertToIrExpression(result).cast(result, result.typeRef, whenExpressionType)
}
val irResult = convertToIrExpression(result).insertImplicitCast(result, result.typeRef, whenExpressionType)
if (condition is FirElseIfTrueCondition) {
IrElseBranchImpl(IrConstImpl.boolean(irResult.startOffset, irResult.endOffset, irBuiltIns.booleanType, true), irResult)
} else {
@@ -2901,6 +2901,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
runTest("compiler/testData/ir/irText/types/nullChecks/implicitNotNullOnPlatformType.kt");
}
@Test
@TestMetadata("nullCheckInElvisRhs.kt")
public void testNullCheckInElvisRhs() throws Exception {
runTest("compiler/testData/ir/irText/types/nullChecks/nullCheckInElvisRhs.kt");
}
@Test
@TestMetadata("nullCheckOnInterfaceDelegation.kt")
public void testNullCheckOnInterfaceDelegation() throws Exception {
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// FIR status: Fail: should have been an exception in 'bar()'
// MODULE: lib
// FILE: RightElvisOperand.java
@@ -0,0 +1,23 @@
Module: lib
Module: main
FILE fqName:<root> fileName:/nullCheckInElvisRhs.kt
FUN name:baz visibility:public modality:FINAL <> () returnType:kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun baz (): kotlin.String? declared in <root>'
CONST Null type=kotlin.Nothing? value=null
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.String declared in <root>'
BLOCK type=kotlin.String origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.String? [val]
CALL 'public final fun baz (): kotlin.String? declared in <root>' type=kotlin.String? origin=null
WHEN type=kotlin.String origin=ELVIS
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 tmp_0: kotlin.String? [val] declared in <root>.test' type=kotlin.String? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null
then: TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public/*package*/ open fun foo (): @[FlexibleNullability] kotlin.String? declared in <root>.RightElvisOperand' type=@[FlexibleNullability] kotlin.String? origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_0: kotlin.String? [val] declared in <root>.test' type=kotlin.String? origin=null
@@ -0,0 +1,17 @@
// MODULE: lib
// MODULE: main
// FILE: nullCheckInElvisRhs.kt
fun baz(): String? {
return null
}
fun test(): String {
return { // BLOCK
val <elvis>: String? = baz()
when {
EQEQ(arg0 = <elvis>, arg1 = null) -> foo() /*!! String */
else -> <elvis>
}
}
}
@@ -0,0 +1,23 @@
Module: lib
Module: main
FILE fqName:<root> fileName:/nullCheckInElvisRhs.kt
FUN name:baz visibility:public modality:FINAL <> () returnType:kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun baz (): kotlin.String? declared in <root>'
CONST Null type=kotlin.Nothing? value=null
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.String declared in <root>'
BLOCK type=kotlin.String origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.String? [val]
CALL 'public final fun baz (): kotlin.String? declared in <root>' type=kotlin.String? origin=null
WHEN type=kotlin.String origin=null
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 tmp_0: kotlin.String? [val] declared in <root>.test' type=kotlin.String? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null
then: TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public/*package*/ open fun foo (): @[FlexibleNullability] kotlin.String? declared in <root>.RightElvisOperand' type=@[FlexibleNullability] kotlin.String? origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_0: kotlin.String? [val] declared in <root>.test' type=kotlin.String? origin=null
@@ -0,0 +1,17 @@
// TARGET_BACKEND: JVM
// MODULE: lib
// FILE: RightElvisOperand.java
class RightElvisOperand {
static String foo() {
return null;
}
}
// MODULE: main(lib)
// FILE: nullCheckInElvisRhs.kt
fun baz(): String? = null
fun test(): String = baz() ?: RightElvisOperand.foo()
@@ -0,0 +1,18 @@
// MODULE: lib
// MODULE: main
// FILE: nullCheckInElvisRhs.kt
fun baz(): String? {
return null
}
fun test(): String {
return { // BLOCK
val tmp0_elvis_lhs: String? = baz()
when {
EQEQ(arg0 = tmp0_elvis_lhs, arg1 = null) -> foo() /*!! String */
else -> tmp0_elvis_lhs
}
}
}
@@ -2901,6 +2901,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest {
runTest("compiler/testData/ir/irText/types/nullChecks/implicitNotNullOnPlatformType.kt");
}
@Test
@TestMetadata("nullCheckInElvisRhs.kt")
public void testNullCheckInElvisRhs() throws Exception {
runTest("compiler/testData/ir/irText/types/nullChecks/nullCheckInElvisRhs.kt");
}
@Test
@TestMetadata("nullCheckOnInterfaceDelegation.kt")
public void testNullCheckOnInterfaceDelegation() throws Exception {