From decfaa3ba5e24be6f73f66ebd548b423789d8e81 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 16 Mar 2021 11:15:18 +0300 Subject: [PATCH] JVM_IR KT-44993 preserve inner expression type when fusing if-null --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++ .../runners/ir/Fir2IrTextTestGenerated.java | 6 ++ .../lower/IfNullExpressionsFusionLowering.kt | 18 +++-- .../codegen/box/regressions/kt44993.kt | 15 +++++ .../testData/ir/irText/expressions/kt44993.kt | 13 ++++ .../ir/irText/expressions/kt44993.txt | 66 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++ .../test/runners/ir/IrTextTestGenerated.java | 6 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ 10 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/codegen/box/regressions/kt44993.kt create mode 100644 compiler/testData/ir/irText/expressions/kt44993.kt create mode 100644 compiler/testData/ir/irText/expressions/kt44993.txt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index c918169bb55..d95c02bd570 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -36540,6 +36540,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/regressions/kt4281.kt"); } + @Test + @TestMetadata("kt44993.kt") + public void testKt44993() throws Exception { + runTest("compiler/testData/codegen/box/regressions/kt44993.kt"); + } + @Test @TestMetadata("kt5056.kt") public void testKt5056() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java index 687af753201..8156c086269 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java @@ -1358,6 +1358,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { runTest("compiler/testData/ir/irText/expressions/kt42321.kt"); } + @Test + @TestMetadata("kt44993.kt") + public void testKt44993() throws Exception { + runTest("compiler/testData/ir/irText/expressions/kt44993.kt"); + } + @Test @TestMetadata("kt45022.kt") public void testKt45022() throws Exception { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/IfNullExpressionsFusionLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/IfNullExpressionsFusionLowering.kt index 045e35d732b..8f48c790cc4 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/IfNullExpressionsFusionLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/IfNullExpressionsFusionLowering.kt @@ -8,15 +8,19 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase -import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.builders.createTmpVariable +import org.jetbrains.kotlin.ir.builders.irBlock +import org.jetbrains.kotlin.ir.builders.irGet +import org.jetbrains.kotlin.ir.builders.irIfNull import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNullable -import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.* +import org.jetbrains.kotlin.ir.util.fileOrNull +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid val ifNullExpressionsFusionPhase = makeIrFilePhase( @@ -98,17 +102,17 @@ class IfNullExpressionsFusionLowering(val context: CommonBackendContext) : FileL (!outer.ifNullExpr.isTrivial() && innerKeepsNull != false && innerDiscardsNonNull != false) ) return this return inner.createIrBuilder().irBlock { - val ifNull = outer.substitute(inner.ifNullExpr, innerKeepsNull) - val ifNotNull = outer.substitute(inner.ifNotNullExpr, innerDiscardsNonNull) + val ifNull = outer.substitute(inner.ifNullExpr, innerKeepsNull, inner.type) + val ifNotNull = outer.substitute(inner.ifNotNullExpr, innerDiscardsNonNull, inner.type) +inner.subjectVar +irIfNull(outer.type, irGet(inner.subjectVar), ifNull, ifNotNull) } } - private fun IfNullExpr.substitute(subject: IrExpression, knownNullability: Boolean?): IrExpression = + private fun IfNullExpr.substitute(subject: IrExpression, knownNullability: Boolean?, temporaryVarType: IrType): IrExpression = when (knownNullability) { null -> createIrBuilder().irBlock { - val tmp = createTmpVariable(subject) + val tmp = createTmpVariable(subject, irType = temporaryVarType) val ifNull = ifNullExpr.remap(subjectVar, lazy { tmp }) val ifNotNull = ifNotNullExpr.remap(subjectVar, lazy { tmp }) +irIfNull(type, irGet(tmp), ifNull, ifNotNull) diff --git a/compiler/testData/codegen/box/regressions/kt44993.kt b/compiler/testData/codegen/box/regressions/kt44993.kt new file mode 100644 index 00000000000..8537ec025fe --- /dev/null +++ b/compiler/testData/codegen/box/regressions/kt44993.kt @@ -0,0 +1,15 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FILE: kt44993.kt +fun box(): String = + f(KotlinBox(JavaBox())) + +fun f(r: KotlinBox): String = + r?.data?.element!! + +class KotlinBox(@JvmField val data: T?) + +// FILE: JavaBox.java +public class JavaBox { + public final String element = "OK"; +} diff --git a/compiler/testData/ir/irText/expressions/kt44993.kt b/compiler/testData/ir/irText/expressions/kt44993.kt new file mode 100644 index 00000000000..f0278fdadf3 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt44993.kt @@ -0,0 +1,13 @@ +// FIR_IDENTICAL +// WITH_RUNTIME +// SKIP_KT_DUMP +// FILE: kt44993.kt +fun f(r: KotlinBox): String = + r?.data?.element!! + +class KotlinBox(@JvmField val data: T?) + +// FILE: JavaBox.java +public class JavaBox { + public final String element = "OK"; +} diff --git a/compiler/testData/ir/irText/expressions/kt44993.txt b/compiler/testData/ir/irText/expressions/kt44993.txt new file mode 100644 index 00000000000..765505f370a --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt44993.txt @@ -0,0 +1,66 @@ +FILE fqName: fileName:/kt44993.kt + FUN name:f visibility:public modality:FINAL <> (r:.KotlinBox<.JavaBox>) returnType:kotlin.String + VALUE_PARAMETER name:r index:0 type:.KotlinBox<.JavaBox> + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (r: .KotlinBox<.JavaBox>): kotlin.String declared in ' + CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): T0 of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.String origin=EXCLEXCL + : kotlin.String + arg0: BLOCK type=@[FlexibleNullability] kotlin.String? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.JavaBox? [val] + BLOCK type=.JavaBox? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:.KotlinBox<.JavaBox> [val] + GET_VAR 'r: .KotlinBox<.JavaBox> declared in .f' type=.KotlinBox<.JavaBox> origin=null + WHEN type=.JavaBox? 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_1: .KotlinBox<.JavaBox> [val] declared in .f' type=.KotlinBox<.JavaBox> origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun (): T of .KotlinBox? declared in .KotlinBox' type=.JavaBox? origin=GET_PROPERTY + $this: GET_VAR 'val tmp_1: .KotlinBox<.JavaBox> [val] declared in .f' type=.KotlinBox<.JavaBox> origin=null + WHEN type=@[FlexibleNullability] 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: .JavaBox? [val] declared in .f' type=.JavaBox? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:element type:@[FlexibleNullability] kotlin.String? visibility:public [final]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY + receiver: GET_VAR 'val tmp_0: .JavaBox? [val] declared in .f' type=.JavaBox? origin=null + CLASS CLASS name:KotlinBox modality:FINAL visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.KotlinBox.KotlinBox> + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] + CONSTRUCTOR visibility:public <> (data:T of .KotlinBox?) returnType:.KotlinBox.KotlinBox> [primary] + VALUE_PARAMETER name:data index:0 type:T of .KotlinBox? + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:KotlinBox modality:FINAL visibility:public superTypes:[kotlin.Any]' + PROPERTY name:data visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:data type:T of .KotlinBox? visibility:public [final] + annotations: + JvmField + EXPRESSION_BODY + GET_VAR 'data: T of .KotlinBox? declared in .KotlinBox.' type=T of .KotlinBox? origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.KotlinBox.KotlinBox>) returnType:T of .KotlinBox? + correspondingProperty: PROPERTY name:data visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:.KotlinBox.KotlinBox> + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): T of .KotlinBox? declared in .KotlinBox' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:data type:T of .KotlinBox? visibility:public [final]' type=T of .KotlinBox? origin=null + receiver: GET_VAR ': .KotlinBox.KotlinBox> declared in .KotlinBox.' type=.KotlinBox.KotlinBox> origin=null + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index e9babf01b87..394e3725b59 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -36540,6 +36540,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/regressions/kt4281.kt"); } + @Test + @TestMetadata("kt44993.kt") + public void testKt44993() throws Exception { + runTest("compiler/testData/codegen/box/regressions/kt44993.kt"); + } + @Test @TestMetadata("kt5056.kt") public void testKt5056() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 3a5647bd259..a7e09d0eeac 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -36540,6 +36540,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/regressions/kt4281.kt"); } + @Test + @TestMetadata("kt44993.kt") + public void testKt44993() throws Exception { + runTest("compiler/testData/codegen/box/regressions/kt44993.kt"); + } + @Test @TestMetadata("kt5056.kt") public void testKt5056() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java index 243922a56de..71b9deee00a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java @@ -1358,6 +1358,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest { runTest("compiler/testData/ir/irText/expressions/kt42321.kt"); } + @Test + @TestMetadata("kt44993.kt") + public void testKt44993() throws Exception { + runTest("compiler/testData/ir/irText/expressions/kt44993.kt"); + } + @Test @TestMetadata("kt45022.kt") public void testKt45022() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index d08046d590a..3d1940fdcdd 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -29110,6 +29110,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/regressions/kt4281.kt"); } + @TestMetadata("kt44993.kt") + public void testKt44993() throws Exception { + runTest("compiler/testData/codegen/box/regressions/kt44993.kt"); + } + @TestMetadata("kt5056.kt") public void testKt5056() throws Exception { runTest("compiler/testData/codegen/box/regressions/kt5056.kt");