Implement interop integer conversions to be used with type inference
This commit is contained in:
committed by
SvyatoslavScherbina
parent
757c306341
commit
f65044c7bb
@@ -4,4 +4,46 @@ internal fun decodeFromUtf8(bytes: ByteArray) = String(bytes)
|
|||||||
internal fun encodeToUtf8(str: String) = str.toByteArray()
|
internal fun encodeToUtf8(str: String) = str.toByteArray()
|
||||||
|
|
||||||
fun bitsToFloat(bits: Int): Float = java.lang.Float.intBitsToFloat(bits)
|
fun bitsToFloat(bits: Int): Float = java.lang.Float.intBitsToFloat(bits)
|
||||||
fun bitsToDouble(bits: Long): Double = java.lang.Double.longBitsToDouble(bits)
|
fun bitsToDouble(bits: Long): Double = java.lang.Double.longBitsToDouble(bits)
|
||||||
|
|
||||||
|
// TODO: the functions below should eventually be intrinsified
|
||||||
|
|
||||||
|
inline fun <reified R : Number> Number.signExtend(): R {
|
||||||
|
val returnValueClass = R::class.java
|
||||||
|
when (returnValueClass) {
|
||||||
|
java.lang.Byte::class.java -> if (this is Byte) {
|
||||||
|
return this.toByte() as R
|
||||||
|
}
|
||||||
|
java.lang.Short::class.java -> if (this is Byte || this is Short) {
|
||||||
|
return this.toShort() as R
|
||||||
|
}
|
||||||
|
java.lang.Integer::class.java -> if (this is Byte || this is Short || this is Int) {
|
||||||
|
return this.toInt() as R
|
||||||
|
}
|
||||||
|
java.lang.Long::class.java -> if (this is Byte || this is Short || this is Int || this is Long) {
|
||||||
|
return this.toLong() as R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Error("unable to sign extend ${this.javaClass.simpleName} \"$this\" to ${returnValueClass.simpleName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified R : Number> Number.narrow(): R {
|
||||||
|
val returnValueClass = R::class.java
|
||||||
|
when (returnValueClass) {
|
||||||
|
java.lang.Byte::class.java -> if (this is Byte || this is Short || this is Int || this is Long) {
|
||||||
|
return this.toByte() as R
|
||||||
|
}
|
||||||
|
java.lang.Short::class.java -> if (this is Short || this is Int || this is Long) {
|
||||||
|
return this.toShort() as R
|
||||||
|
}
|
||||||
|
java.lang.Integer::class.java -> if (this is Int || this is Long) {
|
||||||
|
return this.toInt() as R
|
||||||
|
}
|
||||||
|
java.lang.Long::class.java -> if (this is Long) {
|
||||||
|
return this.toLong() as R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Error("unable to narrow ${this.javaClass.simpleName} \"$this\" to ${returnValueClass.simpleName}")
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,4 +21,10 @@ fun encodeToUtf8(str: String): ByteArray {
|
|||||||
external fun bitsToFloat(bits: Int): Float
|
external fun bitsToFloat(bits: Int): Float
|
||||||
|
|
||||||
@Intrinsic
|
@Intrinsic
|
||||||
external fun bitsToDouble(bits: Long): Double
|
external fun bitsToDouble(bits: Long): Double
|
||||||
|
|
||||||
|
@Intrinsic
|
||||||
|
external fun <R : Number> Number.signExtend(): R
|
||||||
|
|
||||||
|
@Intrinsic
|
||||||
|
external fun <R : Number> Number.narrow(): R
|
||||||
|
|||||||
+4
@@ -132,6 +132,10 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
|||||||
|
|
||||||
fun isTriviallyAdaptedFunctionType(type: KotlinType): Boolean =
|
fun isTriviallyAdaptedFunctionType(type: KotlinType): Boolean =
|
||||||
type.isSubtypeOf(trivallyAdaptedFunctionTypeType)
|
type.isSubtypeOf(trivallyAdaptedFunctionTypeType)
|
||||||
|
|
||||||
|
val signExtend = packageScope.getContributedFunctions("signExtend").single()
|
||||||
|
|
||||||
|
val narrow = packageScope.getContributedFunctions("narrow").single()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MemberScope.getContributedVariables(name: String) =
|
private fun MemberScope.getContributedVariables(name: String) =
|
||||||
|
|||||||
+45
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.konan.Context
|
|||||||
import org.jetbrains.kotlin.backend.konan.ValueType
|
import org.jetbrains.kotlin.backend.konan.ValueType
|
||||||
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
|
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
|
||||||
import org.jetbrains.kotlin.backend.konan.reportCompilationError
|
import org.jetbrains.kotlin.backend.konan.reportCompilationError
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.builders.IrBuilder
|
import org.jetbrains.kotlin.ir.builders.IrBuilder
|
||||||
@@ -239,6 +240,50 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interop.signExtend, interop.narrow -> {
|
||||||
|
|
||||||
|
val integerTypePredicates = arrayOf(
|
||||||
|
KotlinBuiltIns::isByte, KotlinBuiltIns::isShort, KotlinBuiltIns::isInt, KotlinBuiltIns::isLong
|
||||||
|
)
|
||||||
|
|
||||||
|
val receiver = expression.extensionReceiver!!
|
||||||
|
val typeOperand = expression.getSingleTypeArgument()
|
||||||
|
|
||||||
|
val receiverTypeIndex = integerTypePredicates.indexOfFirst { it(receiver.type) }
|
||||||
|
val typeOperandIndex = integerTypePredicates.indexOfFirst { it(typeOperand) }
|
||||||
|
|
||||||
|
if (receiverTypeIndex == -1) {
|
||||||
|
context.reportCompilationError("Receiver's type ${receiver.type} is not an integer type",
|
||||||
|
irFile, receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeOperandIndex == -1) {
|
||||||
|
context.reportCompilationError("Type argument $typeOperand is not an integer type",
|
||||||
|
irFile, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
when (descriptor) {
|
||||||
|
interop.signExtend -> if (receiverTypeIndex > typeOperandIndex) {
|
||||||
|
context.reportCompilationError("unable to sign extend ${receiver.type} to $typeOperand",
|
||||||
|
irFile, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
interop.narrow -> if (receiverTypeIndex < typeOperandIndex) {
|
||||||
|
context.reportCompilationError("unable to narrow ${receiver.type} to $typeOperand",
|
||||||
|
irFile, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
val conversionDescriptor = receiver.type.memberScope.getContributedFunctions(
|
||||||
|
Name.identifier("to$typeOperand"), NoLookupLocation.FROM_BACKEND).single()
|
||||||
|
|
||||||
|
builder.irCall(conversionDescriptor).apply {
|
||||||
|
dispatchReceiver = receiver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else -> expression
|
else -> expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
with(serverAddr) {
|
with(serverAddr) {
|
||||||
memset(this.ptr, 0, sockaddr_in.size)
|
memset(this.ptr, 0, sockaddr_in.size)
|
||||||
sin_family.value = AF_INET.toByte()
|
sin_family.value = AF_INET.narrow()
|
||||||
sin_addr.s_addr.value = htons(0).toInt()
|
sin_addr.s_addr.value = htons(0).toInt()
|
||||||
sin_port.value = htons(port)
|
sin_port.value = htons(port)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user