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.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedTypes;
|
|
||||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.HashCode;
|
import org.jetbrains.kotlin.codegen.intrinsics.HashCode;
|
||||||
@@ -148,6 +147,10 @@ public class AsmUtil {
|
|||||||
return primitiveTypeByBoxedType.get(boxedType);
|
return primitiveTypeByBoxedType.get(boxedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isBoxedPrimitiveType(@NotNull Type boxedType) {
|
||||||
|
return primitiveTypeByBoxedType.get(boxedType) != null;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Type unboxUnlessPrimitive(@NotNull Type boxedOrPrimitiveType) {
|
public static Type unboxUnlessPrimitive(@NotNull Type boxedOrPrimitiveType) {
|
||||||
if (isPrimitive(boxedOrPrimitiveType)) return boxedOrPrimitiveType;
|
if (isPrimitive(boxedOrPrimitiveType)) return boxedOrPrimitiveType;
|
||||||
|
|||||||
+5
@@ -67,6 +67,7 @@ class BoxedValueDescriptor(
|
|||||||
|
|
||||||
var isSafeToRemove = true; private set
|
var isSafeToRemove = true; private set
|
||||||
val unboxedType: Type = getUnboxedType(boxedType, generationState)
|
val unboxedType: Type = getUnboxedType(boxedType, generationState)
|
||||||
|
val isInlineClassValue = isInlineClassValue(boxedType)
|
||||||
|
|
||||||
fun getAssociatedInsns() = associatedInsns.toList()
|
fun getAssociatedInsns() = associatedInsns.toList()
|
||||||
|
|
||||||
@@ -120,3 +121,7 @@ fun unboxedTypeOfInlineClass(boxedType: Type, state: GenerationState): Type? {
|
|||||||
val descriptor = state.jvmBackendClassResolver.resolveToClassDescriptors(boxedType).singleOrNull() ?: return null
|
val descriptor = state.jvmBackendClassResolver.resolveToClassDescriptors(boxedType).singleOrNull() ?: return null
|
||||||
return state.typeMapper.mapType(descriptor.defaultType)
|
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))
|
isRangeOrProgression(buildFqNameByInternal(type.internalName))
|
||||||
|
|
||||||
fun AbstractInsnNode.isAreEqualIntrinsicForSameTypedBoxedValues(values: List<BasicValue>) =
|
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
|
if (values.size != 2) return false
|
||||||
val (v1, v2) = values
|
val (v1, v2) = values
|
||||||
return v1 is BoxedBasicValue &&
|
return v1 is BoxedBasicValue &&
|
||||||
v2 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() =
|
fun AbstractInsnNode.isAreEqualIntrinsic() =
|
||||||
@@ -299,7 +300,7 @@ fun canValuesBeUnboxedForAreEqual(values: List<BasicValue>, generationState: Gen
|
|||||||
values.none { getUnboxedType(it.type, generationState) in shouldUseEqualsForWrappers }
|
values.none { getUnboxedType(it.type, generationState) in shouldUseEqualsForWrappers }
|
||||||
|
|
||||||
fun AbstractInsnNode.isJavaLangComparableCompareToForSameTypedBoxedValues(values: List<BasicValue>) =
|
fun AbstractInsnNode.isJavaLangComparableCompareToForSameTypedBoxedValues(values: List<BasicValue>) =
|
||||||
isJavaLangComparableCompareTo() && areSameTypedBoxedValues(values)
|
isJavaLangComparableCompareTo() && areSameTypedPrimitiveBoxedValues(values)
|
||||||
|
|
||||||
fun AbstractInsnNode.isJavaLangComparableCompareTo() =
|
fun AbstractInsnNode.isJavaLangComparableCompareTo() =
|
||||||
isMethodInsnWith(Opcodes.INVOKEINTERFACE) {
|
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:
|
// @TestInlinedKt.class:
|
||||||
// 0 valueOf
|
// 0 valueOf
|
||||||
// 0 Value
|
// 0 Value
|
||||||
// 0 areEqual
|
// 1 areEqual
|
||||||
// 0 INVOKESTATIC InlinedInt\$Erased.box
|
// 2 INVOKESTATIC InlinedInt\$Erased.box
|
||||||
// 0 INVOKEVIRTUAL InlinedInt.unbox
|
// 0 INVOKEVIRTUAL InlinedInt.unbox
|
||||||
|
|
||||||
// FILE: Inline.kt
|
// FILE: Inline.kt
|
||||||
|
|||||||
Generated
+5
@@ -11196,6 +11196,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
|
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")
|
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
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");
|
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")
|
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
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");
|
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")
|
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
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");
|
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")
|
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
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");
|
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")
|
@TestMetadata("correctBoxingForBranchExpressions.kt")
|
||||||
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
public void testCorrectBoxingForBranchExpressions() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/correctBoxingForBranchExpressions.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user