JVM_IR fold safe calls and elvises
This commit is contained in:
committed by
teamcityserver
parent
7370d096ee
commit
9325660f06
+6
@@ -39745,6 +39745,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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
|
@Nested
|
||||||
|
|||||||
+6
@@ -5448,6 +5448,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt");
|
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
|
@Test
|
||||||
@TestMetadata("notNullReceiversInChain.kt")
|
@TestMetadata("notNullReceiversInChain.kt")
|
||||||
public void testNotNullReceiversInChain() throws Exception {
|
public void testNotNullReceiversInChain() throws Exception {
|
||||||
|
|||||||
+162
-68
@@ -31,19 +31,60 @@ val jvmSafeCallFoldingPhase = makeIrFilePhase(
|
|||||||
|
|
||||||
class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLoweringPass {
|
class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLoweringPass {
|
||||||
// Overall idea here is to represent (possibly chained) safe calls as an if-expression in the form:
|
// Overall idea here is to represent (possibly chained) safe calls as an if-expression in the form:
|
||||||
// if ( { val tmp = <safe_receiver>; tmp != null } )
|
// when {
|
||||||
// <safe_call>
|
// { val tmp = <safe_receiver>; tmp != null } -> <safe_call_result>
|
||||||
// else
|
// else -> null
|
||||||
// null
|
// }
|
||||||
// This allows chaining safe calls like 'a?.foo()?.bar()?.qux()':
|
// This allows chaining safe calls like 'a?.foo()?.bar()?.qux()':
|
||||||
// if ( { val tmp1 = a; tmp1 != null } &&
|
// when {
|
||||||
// { val tmp2 = tmp1.foo(); tmp2 != null } &&
|
// { val tmp1 = a; tmp1 != null } &&
|
||||||
// { val tmp3 = tmp2.bar(); tmp3 != null }
|
// { val tmp2 = tmp1.foo(); tmp2 != null } &&
|
||||||
// )
|
// { val tmp3 = tmp2.bar(); tmp3 != null } ->
|
||||||
// tmp3.qux()
|
// tmp3.qux()
|
||||||
// else
|
// else ->
|
||||||
// null
|
// null
|
||||||
// This also allows fusing safe calls with elvises (and some other operations).
|
// }
|
||||||
|
// Folded safe call always has the following form:
|
||||||
|
// when {
|
||||||
|
// <safe_call_condition> -> <safe_call_result>
|
||||||
|
// else -> null
|
||||||
|
// }
|
||||||
|
// Note that <safe_call_result> itself might be nullable.
|
||||||
|
//
|
||||||
|
// Similarly, elvises can be represented in the form:
|
||||||
|
// when {
|
||||||
|
// { val tmp = <elvis_lhs>; tmp != null } ->
|
||||||
|
// tmp
|
||||||
|
// else ->
|
||||||
|
// <elvis_rhs>
|
||||||
|
// }
|
||||||
|
// which also allows chaining.
|
||||||
|
// Folded and possibly chained elvis has the following form:
|
||||||
|
// when {
|
||||||
|
// <elvis_condition_1> -> <elvis_lhs_1>
|
||||||
|
// ...
|
||||||
|
// <elvis_condition_N> -> <elvis_lhs_N>
|
||||||
|
// else -> <elvis_rhs>
|
||||||
|
// }
|
||||||
|
// where <elvis_lhs_k> are guaranteed to be non-null if the corresponding <elvis_condition_k> 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) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildrenVoid(Transformer())
|
irFile.transformChildrenVoid(Transformer())
|
||||||
@@ -107,13 +148,13 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun foldSafeCall(safeCallInfo: SafeCallInfo): IrExpression {
|
private fun foldSafeCall(safeCallInfo: SafeCallInfo): IrExpression {
|
||||||
// Rewrite a safe call in the form:
|
// We have a safe call in the form:
|
||||||
// { // SAFE_CALL
|
// { // SAFE_CALL
|
||||||
// val tmp = <safe_receiver>
|
// val tmp = <safe_receiver>
|
||||||
// if (tmp == null)
|
// when {
|
||||||
// null
|
// tmp == null -> null
|
||||||
// else
|
// else -> <safe_call_result>
|
||||||
// <call[tmp]>
|
// }
|
||||||
// }
|
// }
|
||||||
val safeCallBlock = safeCallInfo.block
|
val safeCallBlock = safeCallInfo.block
|
||||||
val startOffset = safeCallBlock.startOffset
|
val startOffset = safeCallBlock.startOffset
|
||||||
@@ -126,18 +167,20 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
// Chained safe call.
|
// Chained safe call.
|
||||||
// If <safe_receiver> is a FOLDED_SAFE_CALL form, rewrite safe call to:
|
// If <safe_receiver> is a FOLDED_SAFE_CALL form, rewrite safe call to:
|
||||||
// { // FOLDED_SAFE_CALL
|
// { // FOLDED_SAFE_CALL
|
||||||
// if ( <safe_receiver_condition> && { val tmp = <safe_receiver_result>; tmp != null } )
|
// when {
|
||||||
// <call[tmp]>
|
// <safe_receiver_condition> && { val tmp = <safe_receiver_result>; tmp != null } ->
|
||||||
// else
|
// <safe_call_result>
|
||||||
// null
|
// else ->
|
||||||
|
// null
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
// where
|
// where
|
||||||
// <safe_receiver> =
|
// <safe_receiver> =
|
||||||
// { // FOLDED_SAFE_CALL
|
// { // FOLDED_SAFE_CALL
|
||||||
// if ( <safe_receiver_condition> )
|
// when {
|
||||||
// <safe_receiver_result>
|
// <safe_receiver_condition> -> <safe_receiver_result>
|
||||||
// else
|
// else -> null
|
||||||
// null
|
// }
|
||||||
// }
|
// }
|
||||||
val foldedBlock: IrBlock = tmpValInitializer
|
val foldedBlock: IrBlock = tmpValInitializer
|
||||||
val foldedWhen = foldedBlock.statements[0] as IrWhen
|
val foldedWhen = foldedBlock.statements[0] as IrWhen
|
||||||
@@ -162,10 +205,12 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
// Simple safe call.
|
// Simple safe call.
|
||||||
// If <safe_receiver> itself is not a FOLDED_SAFE_CALL form, rewrite safe call to:
|
// If <safe_receiver> itself is not a FOLDED_SAFE_CALL form, rewrite safe call to:
|
||||||
// { // FOLDED_SAFE_CALL
|
// { // FOLDED_SAFE_CALL
|
||||||
// if ( { val tmp = <safe_receiver>; tmp != null } )
|
// when {
|
||||||
// <call[tmp]>
|
// { val tmp = <safe_receiver>; tmp != null } ->
|
||||||
// else
|
// <safe_call_result>
|
||||||
// null
|
// else ->
|
||||||
|
// null
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
val foldedCondition =
|
val foldedCondition =
|
||||||
@@ -203,24 +248,37 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
// Given elvis expression:
|
// Given elvis expression:
|
||||||
// { // ELVIS
|
// { // ELVIS
|
||||||
// val tmp = <elvis_lhs>
|
// val tmp = <elvis_lhs>
|
||||||
// if (tmp == null)
|
// when {
|
||||||
// <elvis_rhs>
|
// tmp == null -> <elvis_lhs>
|
||||||
// else
|
// else -> null
|
||||||
// null
|
// }
|
||||||
// }
|
// }
|
||||||
// where <elvis_lhs> is a folded safe call in the form:
|
// where <elvis_lhs> is a folded safe call in the form:
|
||||||
// { // FOLDED_SAFE_CALL
|
// { // FOLDED_SAFE_CALL
|
||||||
// if ( <safe_call_condition> )
|
// when {
|
||||||
// <safe_call_result>
|
// <safe_call_condition> -> <safe_call_result>
|
||||||
// else
|
// else -> null
|
||||||
// null
|
// }
|
||||||
// }
|
// }
|
||||||
// rewrite it to
|
// rewrite it to
|
||||||
// { // FOLDED_ELVIS
|
// { // FOLDED_ELVIS
|
||||||
// if ( <safe_call_condition> && { val tmp = <safe_call_result>; tmp != null } )
|
// when {
|
||||||
// tmp
|
// <safe_call_condition> && { val tmp = <safe_call_result>; tmp != null } ->
|
||||||
// else
|
// tmp
|
||||||
// <elvis_rhs>
|
// else ->
|
||||||
|
// <elvis_rhs>
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// If <elvis_rhs> is a folded safe call with non-null result, we can inline the underlying 'when':
|
||||||
|
// { // FOLDED_ELVIS
|
||||||
|
// when {
|
||||||
|
// <safe_call_condition> && { val tmp = <safe_call_result>; tmp != null } ->
|
||||||
|
// tmp
|
||||||
|
// <rhs_safe_call_condition> ->
|
||||||
|
// <rhs_safe_call_result>
|
||||||
|
// else ->
|
||||||
|
// null
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
val safeCallWhen = elvisLhs.statements[0] as IrWhen
|
val safeCallWhen = elvisLhs.statements[0] as IrWhen
|
||||||
@@ -236,39 +294,43 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
irValNotNull(startOffset, endOffset, elvisTmpVal)
|
irValNotNull(startOffset, endOffset, elvisTmpVal)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val foldedWhen = IrWhenImpl(
|
val branches = ArrayList<IrBranch>()
|
||||||
startOffset, endOffset, elvisType, JvmLoweredStatementOrigin.FOLDED_ELVIS,
|
branches.add(
|
||||||
listOf(
|
IrBranchImpl(
|
||||||
IrBranchImpl(
|
startOffset, endOffset,
|
||||||
startOffset, endOffset,
|
irAndAnd(safeCallCondition, foldedConditionPart),
|
||||||
irAndAnd(safeCallCondition, foldedConditionPart),
|
IrGetValueImpl(startOffset, endOffset, elvisTmpVal.symbol)
|
||||||
IrGetValueImpl(startOffset, endOffset, elvisTmpVal.symbol)
|
|
||||||
),
|
|
||||||
IrBranchImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
irTrue(startOffset, endOffset),
|
|
||||||
elvisInfo.elvisRhs
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
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 -> {
|
elvisLhs is IrBlock && elvisLhs.origin == JvmLoweredStatementOrigin.FOLDED_ELVIS -> {
|
||||||
// Append branches to the inner elvis:
|
// Append branches to the inner elvis:
|
||||||
// val t = { // FOLDED_ELVIS
|
// val t = { // FOLDED_ELVIS
|
||||||
// if (...) ...
|
// when {
|
||||||
// else if ...
|
// ... <innerElvisBranches> ...
|
||||||
// else <innerElvisRhs>
|
// else -> <innerElvisRhs>
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// when {
|
||||||
|
// t == null -> <outerElvisRhs>
|
||||||
|
// else -> t
|
||||||
// }
|
// }
|
||||||
// if (t != null) t else <outerElvisRhs>
|
|
||||||
// =>
|
// =>
|
||||||
// { // FOLDED_ELVIS
|
// { // FOLDED_ELVIS
|
||||||
// if (...) ...
|
// when {
|
||||||
// else if ...
|
// ... <innerElvisBranches> ...
|
||||||
// else if ( { val t = <innerElvisRhs>; t != null } )
|
// { val t = <innerElvisRhs>; t != null } -> t
|
||||||
// t
|
// else -> <outerElvisRhs>
|
||||||
// else
|
// }
|
||||||
// <outerElvisRhs>
|
|
||||||
// }
|
// }
|
||||||
// TODO maybe we can do somewhat better if we analyze innerElvisRhs as well
|
// TODO maybe we can do somewhat better if we analyze innerElvisRhs as well
|
||||||
val innerElvisWhen = elvisLhs.statements[0] as IrWhen
|
val innerElvisWhen = elvisLhs.statements[0] as IrWhen
|
||||||
@@ -295,11 +357,45 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
return innerElvisWhen.wrapWithBlock(JvmLoweredStatementOrigin.FOLDED_ELVIS)
|
return innerElvisWhen.wrapWithBlock(JvmLoweredStatementOrigin.FOLDED_ELVIS)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return elvisInfo.block
|
// Plain elvis.
|
||||||
|
// { // ELVIS
|
||||||
|
// val tmp = <lhs>
|
||||||
|
// when {
|
||||||
|
// tmp == null -> <rhs>
|
||||||
|
// else -> tmp
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Fold it as:
|
||||||
|
// { // FOLDED_ELVIS
|
||||||
|
// when {
|
||||||
|
// { val tmp = <lhs>; 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 {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
expression.transformChildrenVoid()
|
expression.transformChildrenVoid()
|
||||||
|
|
||||||
@@ -330,10 +426,8 @@ class JvmSafeCallChainFoldingLowering(val context: JvmBackendContext) : FileLowe
|
|||||||
return safeCallWhen.wrapWithBlock(origin = null)
|
return safeCallWhen.wrapWithBlock(origin = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
+2
-2
@@ -14,5 +14,5 @@ class A(val x: String) {
|
|||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 4 IFNULL
|
// 4 IFNULL
|
||||||
// 2 IFNONNULL
|
// 0 IFNONNULL
|
||||||
// 2 ACONST_NULL
|
// 0 ACONST_NULL
|
||||||
|
|||||||
+1
@@ -7,3 +7,4 @@ fun test(xs: IntArray, dx: Int) {
|
|||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 5 ALOAD
|
// 5 ALOAD
|
||||||
// 6 ILOAD
|
// 6 ILOAD
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun test(a: Any?, b: Any?, c: Any) =
|
||||||
|
a ?: b ?: c
|
||||||
|
|
||||||
|
// 2 IFNONNULL
|
||||||
|
// 0 IFNULL
|
||||||
|
// 0 ACONST_NULL
|
||||||
+4
-3
@@ -5,13 +5,14 @@ class C(val s: String)
|
|||||||
fun test(na: A?) =
|
fun test(na: A?) =
|
||||||
na?.b?.c?.s
|
na?.b?.c?.s
|
||||||
|
|
||||||
// 1 POP
|
|
||||||
// 1 ACONST_NULL
|
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 1 DUP
|
// 1 DUP
|
||||||
// 1 IFNULL
|
// 1 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
// 1 ACONST_NULL
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// 3 DUP
|
// 3 DUP
|
||||||
// 3 IFNULL
|
// 3 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
// 1 ACONST_NULL
|
||||||
@@ -6,3 +6,6 @@ fun test(an: A?) = an?.b?.c?.s
|
|||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 0 ASTORE
|
// 0 ASTORE
|
||||||
|
// 1 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
// 1 ACONST_NULL
|
||||||
@@ -6,3 +6,6 @@ fun test(an: A?) = an?.bn?.cn?.s
|
|||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 0 ASTORE
|
// 0 ASTORE
|
||||||
|
// 1 ACONST_NULL
|
||||||
|
// 3 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
|||||||
+3
@@ -12,3 +12,6 @@ object Host {
|
|||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 0 ASTORE
|
// 0 ASTORE
|
||||||
|
// 1 ACONST_NULL
|
||||||
|
// 1 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
+3
@@ -16,3 +16,6 @@ fun test(an: A?) = an?.b?.c?.s
|
|||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 0 ASTORE
|
// 0 ASTORE
|
||||||
|
// 1 ACONST_NULL
|
||||||
|
// 1 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
Vendored
+5
-4
@@ -1,11 +1,12 @@
|
|||||||
fun test(a: Any?, b: Any?, c: String) =
|
fun test(a: Any?, b: Any?, c: String) =
|
||||||
a?.toString() ?: b?.toString() ?: c
|
a?.toString() ?: b?.toString() ?: c
|
||||||
|
|
||||||
// 2 IFNULL
|
|
||||||
// 1 ACONST_NULL
|
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 1 IFNONNULL
|
// 2 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
// 0 ACONST_NULL
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
|
// 2 IFNULL
|
||||||
|
// 1 ACONST_NULL
|
||||||
// 2 IFNONNULL
|
// 2 IFNONNULL
|
||||||
@@ -11,7 +11,11 @@ fun test(a: Any?) =
|
|||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 1 DUP
|
// 1 DUP
|
||||||
// 1 IFNULL
|
// 1 IFNULL
|
||||||
|
// 0 ACONST_NULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// 2 DUP
|
// 2 DUP
|
||||||
// 2 IFNULL
|
// 2 IFNULL
|
||||||
|
// 0 ACONST_NULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
|||||||
+6
@@ -39589,6 +39589,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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
|
@Nested
|
||||||
|
|||||||
+6
@@ -5304,6 +5304,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt");
|
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
|
@Test
|
||||||
@TestMetadata("notNullReceiversInChain.kt")
|
@TestMetadata("notNullReceiversInChain.kt")
|
||||||
public void testNotNullReceiversInChain() throws Exception {
|
public void testNotNullReceiversInChain() throws Exception {
|
||||||
|
|||||||
+6
@@ -39745,6 +39745,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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
|
@Nested
|
||||||
|
|||||||
+6
@@ -5448,6 +5448,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/temporaryVals/arrayCompoundAssignment.kt");
|
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
|
@Test
|
||||||
@TestMetadata("notNullReceiversInChain.kt")
|
@TestMetadata("notNullReceiversInChain.kt")
|
||||||
public void testNotNullReceiversInChain() throws Exception {
|
public void testNotNullReceiversInChain() throws Exception {
|
||||||
|
|||||||
+5
@@ -31687,6 +31687,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/sam")
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+5
@@ -26862,6 +26862,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/sam")
|
||||||
|
|||||||
Generated
+5
@@ -26268,6 +26268,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/sam")
|
||||||
|
|||||||
Generated
+5
@@ -26193,6 +26193,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/sam")
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+5
@@ -15587,6 +15587,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
public void testSafeCallOnLong() throws Exception {
|
public void testSafeCallOnLong() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/safeCall/safeCallOnLong.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/sam")
|
||||||
|
|||||||
Reference in New Issue
Block a user