Enable implicit integer coercion for interop libraries

This commit is contained in:
Svyatoslav Scherbina
2018-08-27 15:03:58 +03:00
committed by SvyatoslavScherbina
parent 5eaaa5bbb9
commit 2c12dcd612
4 changed files with 68 additions and 48 deletions
+6
View File
@@ -36,3 +36,9 @@ dependencies {
compile project(':Interop:Indexer')
compile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
}
compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xuse-experimental=kotlin.ExperimentalUnsignedTypes']
}
}
@@ -732,32 +732,31 @@ class StubGenerator(
}
private fun integerLiteral(size: Int, isSigned: Boolean, value: Long): String? {
if (!isSigned) {
val signedLiteral = integerLiteral(size, true, value)
val converter = when (size) {
1 -> "toUByte"
2 -> "toUShort"
4 -> "toUInt"
8 -> "toULong"
return if (isSigned) {
if (value == Long.MIN_VALUE) {
return "${value + 1} - 1" // Workaround for "The value is out of range" compile error.
}
val narrowedValue: Number = when (size) {
1 -> value.toByte()
2 -> value.toShort()
4 -> value.toInt()
8 -> value
else -> return null
}
return "($signedLiteral).$converter()"
}
narrowedValue.toString()
} else {
val narrowedValue: Any = when (size) {
1 -> value.toUByte()
2 -> value.toUShort()
4 -> value.toUInt()
8 -> value.toULong()
else -> return null
}
if (value == Long.MIN_VALUE) {
return "${value + 1} - 1" // Workaround for "The value is out of range" compile error.
"${narrowedValue}u"
}
val narrowedValue: Number = when (size) {
1 -> value.toByte()
2 -> value.toShort()
4 -> value.toInt()
8 -> value
else -> return null
}
return narrowedValue.toString()
}
private fun floatingLiteral(type: Type, value: Double): String? {
@@ -777,37 +776,41 @@ class StubGenerator(
}
}
private fun topLevelValWithGetter(name: String, type: KotlinType, expressionBody: String): String =
"val ${name.asSimpleName()}: ${type.render(kotlinFile)} get() = $expressionBody"
private fun topLevelConstVal(name: String, type: KotlinType, initializer: String): String =
"const val ${name.asSimpleName()}: ${type.render(kotlinFile)} = $initializer"
private fun generateConstant(constant: ConstantDef) {
val literal = when (constant) {
is IntegerConstantDef -> integerLiteral(constant.type, constant.value) ?: return
is FloatingConstantDef -> floatingLiteral(constant.type, constant.value) ?: return
is StringConstantDef -> constant.value.quoteAsKotlinLiteral()
else -> {
// Not supported yet, ignore:
return
val kotlinName = constant.name
val declaration = when (constant) {
is IntegerConstantDef -> {
val literal = integerLiteral(constant.type, constant.value) ?: return
val kotlinType = mirror(constant.type).argType
when (platform) {
KotlinPlatform.NATIVE -> topLevelConstVal(kotlinName, kotlinType, literal)
// No reason to make it const val with backing field on Kotlin/JVM yet:
KotlinPlatform.JVM -> topLevelValWithGetter(kotlinName, kotlinType, literal)
}
}
is FloatingConstantDef -> {
val literal = floatingLiteral(constant.type, constant.value) ?: return
val kotlinType = mirror(constant.type).argType
topLevelValWithGetter(kotlinName, kotlinType, literal)
}
is StringConstantDef -> {
val literal = constant.value.quoteAsKotlinLiteral()
val kotlinType = KotlinTypes.string
topLevelValWithGetter(kotlinName, kotlinType, literal)
}
else -> return
}
val kotlinType = when (constant) {
is IntegerConstantDef,
is FloatingConstantDef -> mirror(constant.type).argType
out(declaration)
is StringConstantDef -> KotlinTypes.string
else -> {
// Not supported yet, ignore:
return
}
}.render(kotlinFile)
// TODO: improve value rendering.
// TODO: consider using `const` modifier.
// It is not currently possible for floating literals.
// Also it provokes constant propagation which can reduce binary compatibility
// when replacing interop stubs without recompiling the application.
out("val ${constant.name.asSimpleName()}: $kotlinType get() = $literal")
// TODO: consider using `const` modifier in all cases.
// Note: It is not currently possible for floating literals.
}
private fun generateStubs(): List<KotlinStub> {
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.descriptors.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.isInterop
sealed class KonanModuleOrigin {
@@ -18,4 +19,9 @@ object CurrentKonanModuleOrigin: CompiledKonanModuleOrigin()
object SyntheticModulesOrigin : KonanModuleOrigin()
internal fun KonanModuleOrigin.isInteropLibrary(): Boolean = when (this) {
is DeserializedKonanModuleOrigin -> this.library.isInterop
CurrentKonanModuleOrigin, SyntheticModulesOrigin -> false
}
val ModuleDescriptor.konanModuleOrigin get() = this.getCapability(KonanModuleOrigin.CAPABILITY)!!
@@ -6,7 +6,9 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.descriptors.konan.KonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.isInteropLibrary
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ImplicitIntegerCoercion
import org.jetbrains.kotlin.storage.StorageManager
internal object KonanModuleDescriptorFactoryImpl: KonanModuleDescriptorFactory {
@@ -21,7 +23,10 @@ internal object KonanModuleDescriptorFactoryImpl: KonanModuleDescriptorFactory {
name,
storageManager,
builtIns,
capabilities = customCapabilities + mapOf(KonanModuleOrigin.CAPABILITY to origin))
capabilities = customCapabilities + mapOf(
KonanModuleOrigin.CAPABILITY to origin,
ImplicitIntegerCoercion.MODULE_CAPABILITY to origin.isInteropLibrary()
))
override fun createDescriptorAndNewBuiltIns(
name: Name,