Leave boxing for compareTo/areEqual methods for inline classes

Inline classes can override methods and thus introduce side effects
This commit is contained in:
Mikhail Zarechenskiy
2018-07-20 03:05:11 +03:00
parent 4e7718bfff
commit ec9d8e580e
10 changed files with 58 additions and 7 deletions
@@ -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;
@@ -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
}
@@ -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) {