From b9371332d607122033ff219009b7fa5ce10be743 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Mon, 27 Feb 2017 11:13:20 +0700 Subject: [PATCH] backend: fix `==` when both parts conform to `Nothing?` type --- .../konan/lower/BuiltinOperatorLowering.kt | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt index be6855c9110..76cfb27eeeb 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt @@ -5,6 +5,7 @@ import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions import org.jetbrains.kotlin.backend.konan.ir.isNullConst import org.jetbrains.kotlin.backend.konan.util.atMostOne +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrBinaryPrimitiveImpl @@ -73,23 +74,37 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf private fun lowerEqeq(lhs: IrExpression, rhs: IrExpression, startOffset: Int, endOffset: Int): IrExpression { // TODO: optimize boxing? - // TODO: areEqualByValue intrinsics are specially treated by code generator - // and thus can be declared synthetically in the compiler instead of explicitly in the runtime. - - // Find a type-compatible `konan.internal.areEqualByValue` intrinsic: - val equals = builtIns.getKonanInternalFunctions("areEqualByValue").atMostOne { - lhs.type.isSubtypeOf(it.valueParameters[0].type) && rhs.type.isSubtypeOf(it.valueParameters[1].type) - } ?: if (lhs.isNullConst() || rhs.isNullConst()) { - // or compare by reference if left or right part is `null`: - irBuiltins.eqeqeq - } else { - // or use the general implementation: - builtIns.getKonanInternalFunctions("areEqual").single() - } + val equals = selectEqualsFunction(lhs, rhs) return IrCallImpl(startOffset, endOffset, equals).apply { putValueArgument(0, lhs) putValueArgument(1, rhs) } } + + private fun selectEqualsFunction(lhs: IrExpression, rhs: IrExpression): FunctionDescriptor { + val nullableNothingType = builtIns.nullableNothingType + if (lhs.type.isSubtypeOf(nullableNothingType) && rhs.type.isSubtypeOf(nullableNothingType)) { + // Compare by reference if each part is either `Nothing` or `Nothing?`: + return irBuiltins.eqeqeq + } + + // TODO: areEqualByValue intrinsics are specially treated by code generator + // and thus can be declared synthetically in the compiler instead of explicitly in the runtime. + + // Find a type-compatible `konan.internal.areEqualByValue` intrinsic: + builtIns.getKonanInternalFunctions("areEqualByValue").atMostOne { + lhs.type.isSubtypeOf(it.valueParameters[0].type) && rhs.type.isSubtypeOf(it.valueParameters[1].type) + }?.let { + return it + } + + return if (lhs.isNullConst() || rhs.isNullConst()) { + // or compare by reference if left or right part is `null`: + irBuiltins.eqeqeq + } else { + // or use the general implementation: + builtIns.getKonanInternalFunctions("areEqual").single() + } + } }