FIR2IR insert implicit cast on elvis RHS
This commit is contained in:
@@ -292,14 +292,22 @@ class Fir2IrVisitor(
|
|||||||
)
|
)
|
||||||
if (initializer != null) {
|
if (initializer != null) {
|
||||||
irVariable.initializer =
|
irVariable.initializer =
|
||||||
with(implicitCastInserter) {
|
convertToIrExpression(initializer)
|
||||||
convertToIrExpression(initializer).cast(initializer, initializer.typeRef, variable.returnTypeRef)
|
.insertImplicitCast(initializer, initializer.typeRef, variable.returnTypeRef)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
annotationGenerator.generate(irVariable, variable)
|
annotationGenerator.generate(irVariable, variable)
|
||||||
return irVariable
|
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 {
|
override fun visitProperty(property: FirProperty, data: Any?): IrElement {
|
||||||
if (property.isLocal) return visitLocalVariable(property)
|
if (property.isLocal) return visitLocalVariable(property)
|
||||||
val irProperty = declarationStorage.getCachedIrProperty(property)!!
|
val irProperty = declarationStorage.getCachedIrProperty(property)!!
|
||||||
@@ -707,13 +715,15 @@ class Fir2IrVisitor(
|
|||||||
val notNullType = originalType.withNullability(ConeNullability.NOT_NULL, session.typeContext)
|
val notNullType = originalType.withNullability(ConeNullability.NOT_NULL, session.typeContext)
|
||||||
val irBranches = listOf(
|
val irBranches = listOf(
|
||||||
IrBranchImpl(
|
IrBranchImpl(
|
||||||
startOffset, endOffset, primitiveOp2(
|
startOffset, endOffset,
|
||||||
|
primitiveOp2(
|
||||||
startOffset, endOffset, irBuiltIns.eqeqSymbol,
|
startOffset, endOffset, irBuiltIns.eqeqSymbol,
|
||||||
irBuiltIns.booleanType, IrStatementOrigin.EQEQ,
|
irBuiltIns.booleanType, IrStatementOrigin.EQEQ,
|
||||||
irGetLhsValue(),
|
irGetLhsValue(),
|
||||||
IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType)
|
IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType)
|
||||||
),
|
),
|
||||||
convertToIrExpression(elvisExpression.rhs)
|
convertToIrExpression(elvisExpression.rhs)
|
||||||
|
.insertImplicitCast(elvisExpression, elvisExpression.rhs.typeRef, elvisExpression.typeRef)
|
||||||
),
|
),
|
||||||
IrElseBranchImpl(
|
IrElseBranchImpl(
|
||||||
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true),
|
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true),
|
||||||
@@ -815,9 +825,7 @@ class Fir2IrVisitor(
|
|||||||
private fun FirWhenBranch.toIrWhenBranch(whenExpressionType: FirTypeRef): IrBranch {
|
private fun FirWhenBranch.toIrWhenBranch(whenExpressionType: FirTypeRef): IrBranch {
|
||||||
return convertWithOffsets { startOffset, endOffset ->
|
return convertWithOffsets { startOffset, endOffset ->
|
||||||
val condition = condition
|
val condition = condition
|
||||||
val irResult = with(implicitCastInserter) {
|
val irResult = convertToIrExpression(result).insertImplicitCast(result, result.typeRef, whenExpressionType)
|
||||||
convertToIrExpression(result).cast(result, result.typeRef, whenExpressionType)
|
|
||||||
}
|
|
||||||
if (condition is FirElseIfTrueCondition) {
|
if (condition is FirElseIfTrueCondition) {
|
||||||
IrElseBranchImpl(IrConstImpl.boolean(irResult.startOffset, irResult.endOffset, irBuiltIns.booleanType, true), irResult)
|
IrElseBranchImpl(IrConstImpl.boolean(irResult.startOffset, irResult.endOffset, irBuiltIns.booleanType, true), irResult)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Generated
+6
@@ -2901,6 +2901,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
|
|||||||
runTest("compiler/testData/ir/irText/types/nullChecks/implicitNotNullOnPlatformType.kt");
|
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
|
@Test
|
||||||
@TestMetadata("nullCheckOnInterfaceDelegation.kt")
|
@TestMetadata("nullCheckOnInterfaceDelegation.kt")
|
||||||
public void testNullCheckOnInterfaceDelegation() throws Exception {
|
public void testNullCheckOnInterfaceDelegation() throws Exception {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// FIR status: Fail: should have been an exception in 'bar()'
|
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: RightElvisOperand.java
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Generated
+6
@@ -2901,6 +2901,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest {
|
|||||||
runTest("compiler/testData/ir/irText/types/nullChecks/implicitNotNullOnPlatformType.kt");
|
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
|
@Test
|
||||||
@TestMetadata("nullCheckOnInterfaceDelegation.kt")
|
@TestMetadata("nullCheckOnInterfaceDelegation.kt")
|
||||||
public void testNullCheckOnInterfaceDelegation() throws Exception {
|
public void testNullCheckOnInterfaceDelegation() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user