Support custom 'equals' for inline classes
This commit is contained in:
committed by
SvyatoslavScherbina
parent
8f1b94f38b
commit
a52dd55d42
+23
-1
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
|
||||
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.ir.builders.*
|
||||
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.util.irCall
|
||||
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.isNothing
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.defaultOrNullableType
|
||||
import org.jetbrains.kotlin.ir.util.isNullConst
|
||||
import org.jetbrains.kotlin.ir.util.simpleFunctions
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
@@ -116,6 +120,8 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
|
||||
extensionReceiver = expression
|
||||
}
|
||||
|
||||
private val anyEquals = irBuiltins.anyClass.owner.simpleFunctions().single { it.name.asString() == "equals" }
|
||||
|
||||
private fun lowerEqeq(expression: IrCall): IrExpression {
|
||||
// TODO: optimize boxing?
|
||||
|
||||
@@ -133,7 +139,7 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
|
||||
|
||||
if (expression.symbol == irBuiltins.eqeqSymbol) {
|
||||
lhs.type.getInlinedClass()?.let {
|
||||
if (it == rhs.type.getInlinedClass()) {
|
||||
if (it == rhs.type.getInlinedClass() && inlinedClassHasDefaultEquals(it)) {
|
||||
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(
|
||||
descriptor: FunctionDescriptor,
|
||||
rhs: IrExpression,
|
||||
|
||||
Reference in New Issue
Block a user