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.*
|
||||||
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user