Support custom 'equals' for inline classes

This commit is contained in:
Svyatoslav Scherbina
2018-08-23 14:41:35 +03:00
committed by SvyatoslavScherbina
parent 8f1b94f38b
commit a52dd55d42
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSubtypeOf import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSubtypeOf
import org.jetbrains.kotlin.backend.konan.irasdescriptors.overrides
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -37,11 +39,13 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.defaultOrNullableType import org.jetbrains.kotlin.ir.util.defaultOrNullableType
import org.jetbrains.kotlin.ir.util.isNullConst import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
/** /**
@@ -116,6 +120,8 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
extensionReceiver = expression extensionReceiver = expression
} }
private val anyEquals = irBuiltins.anyClass.owner.simpleFunctions().single { it.name.asString() == "equals" }
private fun lowerEqeq(expression: IrCall): IrExpression { private fun lowerEqeq(expression: IrCall): IrExpression {
// TODO: optimize boxing? // TODO: optimize boxing?
@@ -133,7 +139,7 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
if (expression.symbol == irBuiltins.eqeqSymbol) { if (expression.symbol == irBuiltins.eqeqSymbol) {
lhs.type.getInlinedClass()?.let { lhs.type.getInlinedClass()?.let {
if (it == rhs.type.getInlinedClass()) { if (it == rhs.type.getInlinedClass() && inlinedClassHasDefaultEquals(it)) {
return genInlineClassEquals(expression.descriptor, rhs, lhs) return genInlineClassEquals(expression.descriptor, rhs, lhs)
} }
} }
@@ -143,6 +149,22 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
} }
} }
private fun inlinedClassHasDefaultEquals(irClass: IrClass): Boolean {
if (!irClass.descriptor.isInline) {
// Implicitly-inlined class, e.g. primitive one.
return true
}
val equals = irClass.simpleFunctions()
.single { it.name.asString() == "equals" && it.valueParameters.size == 1 && it.overrides(anyEquals) }
// Note: this is not absolutely correct for inline class from other module
// since custom equals implementation can be added after compilation but before linking.
// TODO: reimplement after inline classes get properly designed `equals` operator.
// see https://youtrack.jetbrains.com/issue/KT-26354.
return equals.descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
}
fun IrBuilderWithScope.genInlineClassEquals( fun IrBuilderWithScope.genInlineClassEquals(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
rhs: IrExpression, rhs: IrExpression,