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 294c0315772..b645cf81000 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 @@ -39745,6 +39745,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @Test + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @Nested diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 3ea300b31d6..454d62ef42d 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -5448,6 +5448,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt"); } + @Test + @TestMetadata("elvisChain.kt") + public void testElvisChain() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/temporaryVals/elvisChain.kt"); + } + @Test @TestMetadata("notNullReceiversInChain.kt") public void testNotNullReceiversInChain() throws Exception { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt index d1b332c7a7b..2a885412c0d 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt @@ -31,19 +31,60 @@ val jvmSafeCallFoldingPhase = makeIrFilePhase( class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLoweringPass { // Overall idea here is to represent (possibly chained) safe calls as an if-expression in the form: - // if ( { val tmp = ; tmp != null } ) - // - // else - // null + // when { + // { val tmp = ; tmp != null } -> + // else -> null + // } // This allows chaining safe calls like 'a?.foo()?.bar()?.qux()': - // if ( { val tmp1 = a; tmp1 != null } && - // { val tmp2 = tmp1.foo(); tmp2 != null } && - // { val tmp3 = tmp2.bar(); tmp3 != null } - // ) - // tmp3.qux() - // else - // null - // This also allows fusing safe calls with elvises (and some other operations). + // when { + // { val tmp1 = a; tmp1 != null } && + // { val tmp2 = tmp1.foo(); tmp2 != null } && + // { val tmp3 = tmp2.bar(); tmp3 != null } -> + // tmp3.qux() + // else -> + // null + // } + // Folded safe call always has the following form: + // when { + // -> + // else -> null + // } + // Note that itself might be nullable. + // + // Similarly, elvises can be represented in the form: + // when { + // { val tmp = ; tmp != null } -> + // tmp + // else -> + // + // } + // which also allows chaining. + // Folded and possibly chained elvis has the following form: + // when { + // -> + // ... + // -> + // else -> + // } + // where are guaranteed to be non-null if the corresponding is true. + // + // This allows representing a chain of safe calls and elvises, + // e.g., 'a?.foo() ?: b?.bar()?.qux() ?: c' + // in a folded form: + // when { + // { val tmp1 = a; tmp1 != null } && + // { val tmp2 = tmp1.foo; tmp1 != null } -> + // tmp2 + // { val tmp3 = b; tmp3 != null } && + // { val tmp4 = tmp2.bar(); tmp4 != null } && + // { val tmp5 = tmp4.qux(); tmp5 != null } -> + // tmp5 + // else -> + // c + // } + // which can be further simplified depending on the nullability of subexpressions in 'a?.foo() ?: b?.bar()?.qux() ?: c'. + // In bytecode this produces a chain of temporary STORE-LOAD and IFNULL checks that can be optimized to a compact sequence + // of stack operations and IFNULL checks. override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(Transformer()) @@ -107,13 +148,13 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe } private fun foldSafeCall(safeCallInfo: SafeCallInfo): IrExpression { - // Rewrite a safe call in the form: + // We have a safe call in the form: // { // SAFE_CALL // val tmp = - // if (tmp == null) - // null - // else - // + // when { + // tmp == null -> null + // else -> + // } // } val safeCallBlock = safeCallInfo.block val startOffset = safeCallBlock.startOffset @@ -126,18 +167,20 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe // Chained safe call. // If is a FOLDED_SAFE_CALL form, rewrite safe call to: // { // FOLDED_SAFE_CALL - // if ( && { val tmp = ; tmp != null } ) - // - // else - // null + // when { + // && { val tmp = ; tmp != null } -> + // + // else -> + // null + // } // } // where // = // { // FOLDED_SAFE_CALL - // if ( ) - // - // else - // null + // when { + // -> + // else -> null + // } // } val foldedBlock: IrBlock = tmpValInitializer val foldedWhen = foldedBlock.statements[0] as IrWhen @@ -162,10 +205,12 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe // Simple safe call. // If itself is not a FOLDED_SAFE_CALL form, rewrite safe call to: // { // FOLDED_SAFE_CALL - // if ( { val tmp = ; tmp != null } ) - // - // else - // null + // when { + // { val tmp = ; tmp != null } -> + // + // else -> + // null + // } // } val foldedCondition = @@ -203,24 +248,37 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe // Given elvis expression: // { // ELVIS // val tmp = - // if (tmp == null) - // - // else - // null + // when { + // tmp == null -> + // else -> null + // } // } // where is a folded safe call in the form: // { // FOLDED_SAFE_CALL - // if ( ) - // - // else - // null + // when { + // -> + // else -> null + // } // } // rewrite it to // { // FOLDED_ELVIS - // if ( && { val tmp = ; tmp != null } ) - // tmp - // else - // + // when { + // && { val tmp = ; tmp != null } -> + // tmp + // else -> + // + // } + // } + // If is a folded safe call with non-null result, we can inline the underlying 'when': + // { // FOLDED_ELVIS + // when { + // && { val tmp = ; tmp != null } -> + // tmp + // -> + // + // else -> + // null + // } // } val safeCallWhen = elvisLhs.statements[0] as IrWhen @@ -236,39 +294,43 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe irValNotNull(startOffset, endOffset, elvisTmpVal) ) ) - val foldedWhen = IrWhenImpl( - startOffset, endOffset, elvisType, JvmLoweredStatementOrigin.FOLDED_ELVIS, - listOf( - IrBranchImpl( - startOffset, endOffset, - irAndAnd(safeCallCondition, foldedConditionPart), - IrGetValueImpl(startOffset, endOffset, elvisTmpVal.symbol) - ), - IrBranchImpl( - startOffset, endOffset, - irTrue(startOffset, endOffset), - elvisInfo.elvisRhs - ) + val branches = ArrayList() + branches.add( + IrBranchImpl( + startOffset, endOffset, + irAndAnd(safeCallCondition, foldedConditionPart), + IrGetValueImpl(startOffset, endOffset, elvisTmpVal.symbol) ) ) - return foldedWhen.wrapWithBlock(JvmLoweredStatementOrigin.FOLDED_ELVIS) + val elvisRhs = elvisInfo.elvisRhs + if (elvisRhs.isFoldedSafeCallWithNonNullResult()) { + val rhsInnerWhen = (elvisRhs as IrBlock).statements[0] as IrWhen + branches.addAll(rhsInnerWhen.branches) + } else { + branches.add(IrBranchImpl(startOffset, endOffset, irTrue(startOffset, endOffset), elvisInfo.elvisRhs)) + } + return IrWhenImpl(startOffset, endOffset, elvisType, JvmLoweredStatementOrigin.FOLDED_ELVIS, branches) + .wrapWithBlock(JvmLoweredStatementOrigin.FOLDED_ELVIS) } elvisLhs is IrBlock && elvisLhs.origin == JvmLoweredStatementOrigin.FOLDED_ELVIS -> { // Append branches to the inner elvis: // val t = { // FOLDED_ELVIS - // if (...) ... - // else if ... - // else + // when { + // ... ... + // else -> + // } + // } + // when { + // t == null -> + // else -> t // } - // if (t != null) t else // => // { // FOLDED_ELVIS - // if (...) ... - // else if ... - // else if ( { val t = ; t != null } ) - // t - // else - // + // when { + // ... ... + // { val t = ; t != null } -> t + // else -> + // } // } // TODO maybe we can do somewhat better if we analyze innerElvisRhs as well val innerElvisWhen = elvisLhs.statements[0] as IrWhen @@ -295,11 +357,45 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe return innerElvisWhen.wrapWithBlock(JvmLoweredStatementOrigin.FOLDED_ELVIS) } else -> { - return elvisInfo.block + // Plain elvis. + // { // ELVIS + // val tmp = + // when { + // tmp == null -> + // else -> tmp + // } + // } + // Fold it as: + // { // FOLDED_ELVIS + // when { + // { val tmp = ; tmp != null } -> tmp + // else -> rhs + // } + // } + val newCondition = IrCompositeImpl( + startOffset, endOffset, context.irBuiltIns.booleanType, null, + listOf(elvisTmpVal, irValNotNull(startOffset, endOffset, elvisTmpVal)) + ) + val foldedWhen = IrWhenImpl( + startOffset, endOffset, elvisType, JvmLoweredStatementOrigin.FOLDED_ELVIS, + listOf( + IrBranchImpl(startOffset, endOffset, newCondition, IrGetValueImpl(startOffset, endOffset, elvisTmpVal.symbol)), + IrBranchImpl(startOffset, endOffset, irTrue(startOffset, endOffset), elvisInfo.elvisRhs) + ) + ) + return foldedWhen.wrapWithBlock(JvmLoweredStatementOrigin.FOLDED_ELVIS) } } } + private fun IrExpression.isFoldedSafeCallWithNonNullResult(): Boolean { + if (this !is IrBlock) return false + if (this.origin != JvmLoweredStatementOrigin.FOLDED_SAFE_CALL) return false + val innerWhen = this.statements[0] as? IrWhen ?: return false + val safeCallResult = innerWhen.branches[0].result + return !safeCallResult.type.isNullable() + } + override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid() @@ -330,10 +426,8 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe return safeCallWhen.wrapWithBlock(origin = null) } } - return expression } - } } diff --git a/compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt b/compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt new file mode 100644 index 00000000000..f49b1775b33 --- /dev/null +++ b/compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt @@ -0,0 +1,8 @@ +fun String.foo(): String? = null + +fun test(a: String?, b: String?, c: String) = + a ?: b?.foo() ?: c +// = (a ?: b?.boo()) ?: c +// Here 'b?.foo()' returns null, which may break elvis semantics if we fold it carelessly. + +fun box() = test(null, "abc", "OK") diff --git a/compiler/testData/codegen/bytecodeText/nullCheckOptimization/safeCallAndElvisChains.kt b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/safeCallAndElvisChains.kt index 8279e0aa77f..f2904a71e69 100644 --- a/compiler/testData/codegen/bytecodeText/nullCheckOptimization/safeCallAndElvisChains.kt +++ b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/safeCallAndElvisChains.kt @@ -14,5 +14,5 @@ class A(val x: String) { // JVM_IR_TEMPLATES // 4 IFNULL -// 2 IFNONNULL -// 2 ACONST_NULL +// 0 IFNONNULL +// 0 ACONST_NULL diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt index e651f964854..466acf44d96 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt @@ -7,3 +7,4 @@ fun test(xs: IntArray, dx: Int) { // JVM_IR_TEMPLATES // 5 ALOAD // 6 ILOAD + diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/elvisChain.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/elvisChain.kt new file mode 100644 index 00000000000..46c012cbf47 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/elvisChain.kt @@ -0,0 +1,6 @@ +fun test(a: Any?, b: Any?, c: Any) = + a ?: b ?: c + +// 2 IFNONNULL +// 0 IFNULL +// 0 ACONST_NULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/notNullReceiversInChain.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/notNullReceiversInChain.kt index 3cafe35b020..d6e064aaf13 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/notNullReceiversInChain.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/notNullReceiversInChain.kt @@ -5,13 +5,14 @@ class C(val s: String) fun test(na: A?) = na?.b?.c?.s -// 1 POP -// 1 ACONST_NULL - // JVM_IR_TEMPLATES // 1 DUP // 1 IFNULL +// 0 IFNONNULL +// 1 ACONST_NULL // JVM_TEMPLATES // 3 DUP -// 3 IFNULL \ No newline at end of file +// 3 IFNULL +// 0 IFNONNULL +// 1 ACONST_NULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain1.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain1.kt index 1e73d132ae4..ea11b7b7fca 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain1.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain1.kt @@ -6,3 +6,6 @@ fun test(an: A?) = an?.b?.c?.s // JVM_IR_TEMPLATES // 0 ASTORE +// 1 IFNULL +// 0 IFNONNULL +// 1 ACONST_NULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain2.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain2.kt index a49bc8b8f09..a4e04df216c 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain2.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChain2.kt @@ -6,3 +6,6 @@ fun test(an: A?) = an?.bn?.cn?.s // JVM_IR_TEMPLATES // 0 ASTORE +// 1 ACONST_NULL +// 3 IFNULL +// 0 IFNONNULL diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt1.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt1.kt index 793b4416fd8..371b59cd72b 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt1.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt1.kt @@ -12,3 +12,6 @@ object Host { // JVM_IR_TEMPLATES // 0 ASTORE +// 1 ACONST_NULL +// 1 IFNULL +// 0 IFNONNULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt2.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt2.kt index b7ea20331f6..c212874612e 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt2.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallChainMemberExt2.kt @@ -16,3 +16,6 @@ fun test(an: A?) = an?.b?.c?.s // JVM_IR_TEMPLATES // 0 ASTORE +// 1 ACONST_NULL +// 1 IFNULL +// 0 IFNONNULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallElvisSafeCallElvisSomething.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallElvisSafeCallElvisSomething.kt index e7be3a06428..d66af2f6b28 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallElvisSafeCallElvisSomething.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallElvisSafeCallElvisSomething.kt @@ -1,11 +1,12 @@ fun test(a: Any?, b: Any?, c: String) = a?.toString() ?: b?.toString() ?: c -// 2 IFNULL -// 1 ACONST_NULL - // JVM_IR_TEMPLATES -// 1 IFNONNULL +// 2 IFNULL +// 0 IFNONNULL +// 0 ACONST_NULL // JVM_TEMPLATES +// 2 IFNULL +// 1 ACONST_NULL // 2 IFNONNULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallWithElvis.kt b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallWithElvis.kt index 71ed94a17f7..c7023427017 100644 --- a/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallWithElvis.kt +++ b/compiler/testData/codegen/bytecodeText/temporaryVals/safeCallWithElvis.kt @@ -11,7 +11,11 @@ fun test(a: Any?) = // JVM_IR_TEMPLATES // 1 DUP // 1 IFNULL +// 0 ACONST_NULL +// 0 IFNONNULL // JVM_TEMPLATES // 2 DUP // 2 IFNULL +// 0 ACONST_NULL +// 0 IFNONNULL 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 2fa81eb0be4..fc0255246e5 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 @@ -39589,6 +39589,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @Test + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index f5cbc671149..6dd6c4eb4a9 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -5304,6 +5304,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt"); } + @Test + @TestMetadata("elvisChain.kt") + public void testElvisChain() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/temporaryVals/elvisChain.kt"); + } + @Test @TestMetadata("notNullReceiversInChain.kt") public void testNotNullReceiversInChain() 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 e160fc79670..0d8b499ed65 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 @@ -39745,6 +39745,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @Test + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index 4a7f2cfbdac..c8acaaa4ceb 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -5448,6 +5448,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt"); } + @Test + @TestMetadata("elvisChain.kt") + public void testElvisChain() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/temporaryVals/elvisChain.kt"); + } + @Test @TestMetadata("notNullReceiversInChain.kt") public void testNotNullReceiversInChain() 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 e9fb17b3a20..bd763a90355 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -31687,6 +31687,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @TestMetadata("compiler/testData/codegen/box/sam") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 054f0b82d44..b1303f6a644 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -26862,6 +26862,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @TestMetadata("compiler/testData/codegen/box/sam") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 29ca6f7e833..7e51c515d8d 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -26268,6 +26268,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @TestMetadata("compiler/testData/codegen/box/sam") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 5ba8f7f7a79..6359060c950 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -26193,6 +26193,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @TestMetadata("compiler/testData/codegen/box/sam") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 52f80c67ff4..a8ce3dfa852 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -15587,6 +15587,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest public void testSafeCallOnLong() throws Exception { runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt"); } + + @TestMetadata("safeCallWithElvisFolding.kt") + public void testSafeCallWithElvisFolding() throws Exception { + runTest("compiler/testData/codegen/box/safeCall/safeCallWithElvisFolding.kt"); + } } @TestMetadata("compiler/testData/codegen/box/sam")