From d5142220d2304d9315a0449df1e6d88958bbd295 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 24 Aug 2018 17:14:33 +0300 Subject: [PATCH] Make kotlinx.cinterop.convert follow C rules --- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 10 +++++ .../backend/konan/lower/InteropLowering.kt | 38 +++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index ce74ac1006a..509fa9592bb 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -149,6 +149,16 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val allIntegerClasses = signedIntegerClasses + unsignedIntegerClasses + val unsignedToSignedOfSameBitWidth = unsignedIntegerClasses.associate { + it to when (it) { + uByte -> byte + uShort -> short + uInt -> int + uLong -> long + else -> error(it.descriptor) + } + } + val integerConversions = allIntegerClasses.flatMap { fromClass -> allIntegerClasses.map { toClass -> val name = Name.identifier("to${toClass.descriptor.name.asString().capitalize()}") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index aec3e7d2ad1..f7f3c21753f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -906,21 +906,20 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB val integerClasses = symbols.allIntegerClasses val typeOperand = expression.getTypeArgument(0)!! val receiverType = expression.symbol.owner.extensionReceiverParameter!!.type - val receiverClass = receiverType.classifierOrFail as IrClassSymbol - assert(receiverClass in integerClasses) + val source = receiverType.classifierOrFail as IrClassSymbol + assert(source in integerClasses) if (typeOperand is IrSimpleType && typeOperand.classifier in integerClasses && !typeOperand.hasQuestionMark) { - val typeOperandClass = typeOperand.classifier as IrClassSymbol + val target = typeOperand.classifier as IrClassSymbol + val valueToConvert = expression.extensionReceiver!! - val conversion = symbols.integerConversions[receiverClass to typeOperandClass]!!.owner - - builder.irCall(conversion).apply { - val valueToConvert = expression.extensionReceiver!! - if (conversion.dispatchReceiverParameter != null) { - dispatchReceiver = valueToConvert - } else { - extensionReceiver = valueToConvert - } + if (source in symbols.signedIntegerClasses && target in symbols.unsignedIntegerClasses) { + // Default Kotlin signed-to-unsigned widening integer conversions don't follow C rules. + val signedTarget = symbols.unsignedToSignedOfSameBitWidth[target]!! + val widened = builder.irConvertInteger(source, signedTarget, valueToConvert) + builder.irConvertInteger(signedTarget, target, widened) + } else { + builder.irConvertInteger(source, target, valueToConvert) } } else { context.reportCompilationError( @@ -987,6 +986,21 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB } } + private fun IrBuilderWithScope.irConvertInteger( + source: IrClassSymbol, + target: IrClassSymbol, + value: IrExpression + ): IrExpression { + val conversion = symbols.integerConversions[source to target]!! + return irCall(conversion.owner).apply { + if (conversion.owner.dispatchReceiverParameter != null) { + dispatchReceiver = value + } else { + extensionReceiver = value + } + } + } + private fun IrType.ensureSupportedInCallbacks(isReturnType: Boolean, reportError: (String) -> Nothing) { this.checkCTypeNullability(reportError)