Make kotlinx.cinterop.convert follow C rules

This commit is contained in:
Svyatoslav Scherbina
2018-08-24 17:14:33 +03:00
committed by SvyatoslavScherbina
parent 872deb205c
commit d5142220d2
2 changed files with 36 additions and 12 deletions
@@ -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()}")
@@ -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)