Get rid of redundant boxing when comparing inline class instances
^KT-33722: Fixed
This commit is contained in:
committed by
teamcity
parent
e5ce32feeb
commit
5ec2f1ad92
+6
@@ -3835,6 +3835,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
|
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt33722.kt")
|
||||||
|
public void testKt33722() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/kt33722.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("mangledInlineClassInterfaceImplementation.kt")
|
@TestMetadata("mangledInlineClassInterfaceImplementation.kt")
|
||||||
public void testMangledInlineClassInterfaceImplementation() throws Exception {
|
public void testMangledInlineClassInterfaceImplementation() throws Exception {
|
||||||
|
|||||||
+30
-12
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.transformStatement
|
import org.jetbrains.kotlin.ir.transformStatement
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -344,32 +345,49 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass
|
|||||||
coerceInlineClasses(arg, expression.symbol.owner.dispatchReceiverParameter!!.type, expression.type)
|
coerceInlineClasses(arg, expression.symbol.owner.dispatchReceiverParameter!!.type, expression.type)
|
||||||
}
|
}
|
||||||
// Specialize calls to equals when the left argument is a value of inline class type.
|
// Specialize calls to equals when the left argument is a value of inline class type.
|
||||||
expression.isSpecializedInlineClassEqEq -> {
|
expression.isSpecializedInlineClassEqEq || expression.isSpecializedInlineClassEquals -> {
|
||||||
expression.transformChildrenVoid()
|
expression.transformChildrenVoid()
|
||||||
|
val leftOp: IrExpression
|
||||||
|
val rightOp: IrExpression
|
||||||
|
if (expression.isSpecializedInlineClassEqEq) {
|
||||||
|
leftOp = expression.getValueArgument(0)!!
|
||||||
|
rightOp = expression.getValueArgument(1)!!
|
||||||
|
} else {
|
||||||
|
leftOp = expression.dispatchReceiver!!
|
||||||
|
rightOp = expression.getValueArgument(0)!!
|
||||||
|
}
|
||||||
context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
||||||
.specializeEqualsCall(expression.getValueArgument(0)!!, expression.getValueArgument(1)!!)
|
.specializeEqualsCall(leftOp, rightOp)
|
||||||
?: expression
|
?: expression
|
||||||
}
|
}
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
super.visitCall(expression)
|
super.visitCall(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val IrCall.isSpecializedInlineClassEquals: Boolean
|
||||||
|
get() {
|
||||||
|
return isSpecializedInlineClassEqualityCheck { symbol.owner.isEquals() }
|
||||||
|
}
|
||||||
|
|
||||||
private val IrCall.isSpecializedInlineClassEqEq: Boolean
|
private val IrCall.isSpecializedInlineClassEqEq: Boolean
|
||||||
get() {
|
get() {
|
||||||
// Note that reference equality (x === y) is not allowed on values of inline class type,
|
// Note that reference equality (x === y) is not allowed on values of inline class type,
|
||||||
// so it is enough to check for eqeq.
|
// so it is enough to check for eqeq.
|
||||||
if (symbol != context.irBuiltIns.eqeqSymbol)
|
return isSpecializedInlineClassEqualityCheck { symbol == context.irBuiltIns.eqeqSymbol }
|
||||||
return false
|
|
||||||
|
|
||||||
val leftClass = getValueArgument(0)?.type?.classOrNull?.owner?.takeIf { it.isSingleFieldValueClass }
|
|
||||||
?: return false
|
|
||||||
|
|
||||||
// Before version 1.4, we cannot rely on the Result.equals-impl0 method
|
|
||||||
return (leftClass.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME) ||
|
|
||||||
context.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun IrCall.isSpecializedInlineClassEqualityCheck(calleePredicate: (IrSimpleFunctionSymbol) -> Boolean): Boolean {
|
||||||
|
|
||||||
|
if (!calleePredicate(symbol)) return false
|
||||||
|
|
||||||
|
val leftClass = getValueArgument(0)?.type?.classOrNull?.owner?.takeIf { it.isSingleFieldValueClass }
|
||||||
|
?: return false
|
||||||
|
|
||||||
|
// Before version 1.4, we cannot rely on the Result.equals-impl0 method
|
||||||
|
return (leftClass.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME) ||
|
||||||
|
context.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField): IrExpression {
|
override fun visitGetField(expression: IrGetField): IrExpression {
|
||||||
val field = expression.symbol.owner
|
val field = expression.symbol.owner
|
||||||
val parent = field.parent
|
val parent = field.parent
|
||||||
|
|||||||
+5
-1
@@ -9,6 +9,10 @@ fun testZ(z: Z, a: Any?) = z.equals(a)
|
|||||||
fun testNZ(z: Z?) = z?.equals(z)
|
fun testNZ(z: Z?) = z?.equals(z)
|
||||||
|
|
||||||
// @TestKt.class:
|
// @TestKt.class:
|
||||||
|
// JVM_IR_TEMPLATES
|
||||||
// 0 INVOKESTATIC Z\$Erased\.equals
|
// 0 INVOKESTATIC Z\$Erased\.equals
|
||||||
// 0 INVOKESTATIC Z\-Erased\.equals
|
// 0 INVOKESTATIC Z\-Erased\.equals
|
||||||
// 3 INVOKESTATIC Z\.equals-impl \(ILjava/lang/Object;\)Z
|
// 1 INVOKESTATIC Z\.equals-impl0 \(II\)Z
|
||||||
|
// 1 INVOKESTATIC Z\.equals-impl \(ILjava/lang/Object;\)Z
|
||||||
|
// 1 INVOKEVIRTUAL Z.equals
|
||||||
|
// 0 INVOKEVIRTUAL Z.unbox-impl
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val result = Result.success("yes!")
|
||||||
|
val other = Result.success("nope")
|
||||||
|
|
||||||
|
result == other
|
||||||
|
result != other
|
||||||
|
|
||||||
|
result.equals(other)
|
||||||
|
!result.equals(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK_BYTECODE_TEXT
|
||||||
|
// 0 INVOKESTATIC kotlin/Result.box-impl
|
||||||
|
// 4 INVOKESTATIC kotlin/Result.equals-impl0
|
||||||
+6
@@ -3835,6 +3835,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
|
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt33722.kt")
|
||||||
|
public void testKt33722() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/kt33722.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("mangledInlineClassInterfaceImplementation.kt")
|
@TestMetadata("mangledInlineClassInterfaceImplementation.kt")
|
||||||
public void testMangledInlineClassInterfaceImplementation() throws Exception {
|
public void testMangledInlineClassInterfaceImplementation() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user