Leave boxing for compareTo/areEqual methods for inline classes
Inline classes can override methods and thus introduce side effects
This commit is contained in:
@@ -15,7 +15,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.HashCode;
|
||||
@@ -148,6 +147,10 @@ public class AsmUtil {
|
||||
return primitiveTypeByBoxedType.get(boxedType);
|
||||
}
|
||||
|
||||
public static boolean isBoxedPrimitiveType(@NotNull Type boxedType) {
|
||||
return primitiveTypeByBoxedType.get(boxedType) != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type unboxUnlessPrimitive(@NotNull Type boxedOrPrimitiveType) {
|
||||
if (isPrimitive(boxedOrPrimitiveType)) return boxedOrPrimitiveType;
|
||||
|
||||
+5
@@ -67,6 +67,7 @@ class BoxedValueDescriptor(
|
||||
|
||||
var isSafeToRemove = true; private set
|
||||
val unboxedType: Type = getUnboxedType(boxedType, generationState)
|
||||
val isInlineClassValue = isInlineClassValue(boxedType)
|
||||
|
||||
fun getAssociatedInsns() = associatedInsns.toList()
|
||||
|
||||
@@ -120,3 +121,7 @@ fun unboxedTypeOfInlineClass(boxedType: Type, state: GenerationState): Type? {
|
||||
val descriptor = state.jvmBackendClassResolver.resolveToClassDescriptors(boxedType).singleOrNull() ?: return null
|
||||
return state.typeMapper.mapType(descriptor.defaultType)
|
||||
}
|
||||
|
||||
private fun isInlineClassValue(boxedType: Type): Boolean {
|
||||
return !AsmUtil.isBoxedPrimitiveType(boxedType) && boxedType != AsmTypes.K_CLASS_TYPE
|
||||
}
|
||||
|
||||
+5
-4
@@ -276,14 +276,15 @@ fun isProgressionClass(type: Type) =
|
||||
isRangeOrProgression(buildFqNameByInternal(type.internalName))
|
||||
|
||||
fun AbstractInsnNode.isAreEqualIntrinsicForSameTypedBoxedValues(values: List<BasicValue>) =
|
||||
isAreEqualIntrinsic() && areSameTypedBoxedValues(values)
|
||||
isAreEqualIntrinsic() && areSameTypedPrimitiveBoxedValues(values)
|
||||
|
||||
fun areSameTypedBoxedValues(values: List<BasicValue>): Boolean {
|
||||
fun areSameTypedPrimitiveBoxedValues(values: List<BasicValue>): Boolean {
|
||||
if (values.size != 2) return false
|
||||
val (v1, v2) = values
|
||||
return v1 is BoxedBasicValue &&
|
||||
v2 is BoxedBasicValue &&
|
||||
v1.descriptor.unboxedType == v2.descriptor.unboxedType
|
||||
v1.descriptor.unboxedType == v2.descriptor.unboxedType &&
|
||||
!v1.descriptor.isInlineClassValue && !v2.descriptor.isInlineClassValue
|
||||
}
|
||||
|
||||
fun AbstractInsnNode.isAreEqualIntrinsic() =
|
||||
@@ -299,7 +300,7 @@ fun canValuesBeUnboxedForAreEqual(values: List<BasicValue>, generationState: Gen
|
||||
values.none { getUnboxedType(it.type, generationState) in shouldUseEqualsForWrappers }
|
||||
|
||||
fun AbstractInsnNode.isJavaLangComparableCompareToForSameTypedBoxedValues(values: List<BasicValue>) =
|
||||
isJavaLangComparableCompareTo() && areSameTypedBoxedValues(values)
|
||||
isJavaLangComparableCompareTo() && areSameTypedPrimitiveBoxedValues(values)
|
||||
|
||||
fun AbstractInsnNode.isJavaLangComparableCompareTo() =
|
||||
isMethodInsnWith(Opcodes.INVOKEINTERFACE) {
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class Foo(val x: Int) : Comparable<Foo> {
|
||||
override fun compareTo(other: Foo): Int {
|
||||
return 10
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val f1 = Foo(42)
|
||||
val ff1: Comparable<Foo> = f1
|
||||
|
||||
if (ff1.compareTo(f1) != 10) return "Fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+2
-2
@@ -20,8 +20,8 @@ fun getAndCheckInlinedInt(a: InlinedInt, b: InlinedInt) =
|
||||
// @TestInlinedKt.class:
|
||||
// 0 valueOf
|
||||
// 0 Value
|
||||
// 0 areEqual
|
||||
// 0 INVOKESTATIC InlinedInt\$Erased.box
|
||||
// 1 areEqual
|
||||
// 2 INVOKESTATIC InlinedInt\$Erased.box
|
||||
// 0 INVOKEVIRTUAL InlinedInt.unbox
|
||||
|
||||
// FILE: Inline.kt
|
||||
|
||||
Generated
+5
@@ -11196,6 +11196,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conformToComparableAndCallInterfaceMethod.kt")
|
||||
public void testConformToComparableAndCallInterfaceMethod() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/conformToComparableAndCallInterfaceMethod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
||||
|
||||
+5
@@ -11196,6 +11196,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conformToComparableAndCallInterfaceMethod.kt")
|
||||
public void testConformToComparableAndCallInterfaceMethod() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/conformToComparableAndCallInterfaceMethod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
||||
|
||||
+5
@@ -11196,6 +11196,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conformToComparableAndCallInterfaceMethod.kt")
|
||||
public void testConformToComparableAndCallInterfaceMethod() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/conformToComparableAndCallInterfaceMethod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
||||
|
||||
+5
@@ -9826,6 +9826,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conformToComparableAndCallInterfaceMethod.kt")
|
||||
public void testConformToComparableAndCallInterfaceMethod() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/conformToComparableAndCallInterfaceMethod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
||||
|
||||
+5
@@ -10831,6 +10831,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conformToComparableAndCallInterfaceMethod.kt")
|
||||
public void testConformToComparableAndCallInterfaceMethod() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/conformToComparableAndCallInterfaceMethod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
||||
|
||||
Reference in New Issue
Block a user