[Interop] Started to work on StubIr -> Metadata translator

Basic support for function, global properties, and type aliases.
Also added AbbreviatedStubType to make translation to metadata a bit easier.
This commit is contained in:
Sergey Bogolepov
2019-11-15 16:36:06 +07:00
committed by Sergey Bogolepov
parent 0712a2ae48
commit ee672f31df
6 changed files with 476 additions and 59 deletions
@@ -6,6 +6,10 @@ package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.indexer.*
// TODO: Replace all usages of these strings with constants.
const val cinteropPackage = "kotlinx.cinterop"
const val cinteropInternalPackage = "$cinteropPackage.internal"
interface StubIrElement {
fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T): R
}
@@ -60,7 +64,10 @@ class TypeParameterStub(
}
interface TypeArgument {
object StarProjection : TypeArgument
object StarProjection : TypeArgument {
override fun toString(): String =
"*"
}
enum class Variance {
INVARIANT,
@@ -72,7 +79,10 @@ interface TypeArgument {
class TypeArgumentStub(
val type: StubType,
val variance: TypeArgument.Variance = TypeArgument.Variance.INVARIANT
) : TypeArgument
) : TypeArgument {
override fun toString(): String =
type.toString()
}
/**
* Represents a source of StubIr element.
@@ -171,8 +181,6 @@ sealed class AnnotationStub(val classifier: Classifier) {
AnnotationStub(Classifier.topLevel("kotlin", "Deprecated"))
private companion object {
const val cinteropInternalPackage = "kotlinx.cinterop.internal"
const val cinteropPackage = "kotlinx.cinterop"
val cCallClassifier = Classifier.topLevel(cinteropInternalPackage, "CCall")
}
}
@@ -37,12 +37,17 @@ class StubIrContext(
}
).precompileHeaders()
// TODO: Used only for JVM.
val jvmFileClassName = if (configuration.pkgName.isEmpty()) {
libName
} else {
configuration.pkgName.substringAfterLast('.')
}
val validPackageName = configuration.pkgName.split(".").joinToString(".") {
if (it.matches(VALID_PACKAGE_NAME_REGEX)) it else "`$it`"
}
private val anonymousStructKotlinNames = mutableMapOf<StructDecl, String>()
private val forbiddenStructNames = run {
@@ -86,6 +91,10 @@ class StubIrContext(
// TODO: consider exporting Objective-C class and protocol forward refs.
}
companion object {
private val VALID_PACKAGE_NAME_REGEX = "[a-zA-Z0-9_.]+".toRegex()
}
}
class StubIrDriver(
@@ -95,6 +104,7 @@ class StubIrDriver(
data class DriverOptions(
val mode: GenerationMode,
val entryPoint: String?,
val moduleName: String,
val outCFile: File,
val outKtFileCreator: () -> File
)
@@ -106,7 +116,7 @@ class StubIrDriver(
}
fun run(): Result {
val (mode, entryPoint, outCFile, outKtFile) = options
val (mode, entryPoint, moduleName, outCFile, outKtFile) = options
val builderResult = StubIrBuilder(context).build()
val bridgeBuilderResult = StubIrBridgeBuilder(context, builderResult).build()
@@ -119,7 +129,7 @@ class StubIrDriver(
GenerationMode.SOURCE_CODE -> {
emitSourceCode(outKtFile(), builderResult, bridgeBuilderResult)
}
GenerationMode.METADATA -> emitMetadata(builderResult)
GenerationMode.METADATA -> emitMetadata(builderResult, moduleName)
}
}
@@ -132,9 +142,8 @@ class StubIrDriver(
return Result.SourceCode
}
private fun emitMetadata(builderResult: StubIrBuilderResult): Result.Metadata {
return Result.Metadata(KlibModuleMetadata("test", emptyList(), emptyList()))
}
private fun emitMetadata(builderResult: StubIrBuilderResult, moduleName: String) =
Result.Metadata(StubIrMetadataEmitter(context, builderResult, moduleName).emit())
private fun emitCFile(context: StubIrContext, cFile: Appendable, entryPoint: String?, nativeBridges: NativeBridges) {
val out = { it: String -> cFile.appendln(it) }
@@ -0,0 +1,331 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import kotlinx.metadata.*
import kotlinx.metadata.klib.*
import org.jetbrains.kotlin.utils.addIfNotNull
class StubIrMetadataEmitter(
private val context: StubIrContext,
private val builderResult: StubIrBuilderResult,
private val moduleName: String
) {
fun emit(): KlibModuleMetadata {
val annotations = emptyList<KmAnnotation>()
val fragments = emitModuleFragments()
return KlibModuleMetadata(moduleName, fragments, annotations)
}
private fun emitModuleFragments(): List<KmModuleFragment> =
ModuleMetadataEmitter(context.configuration.pkgName).let {
builderResult.stubs.accept(it, null)
listOf(it.writeModule())
}
}
/**
* Translates single [StubContainer] to [KmModuleFragment].
*/
internal class ModuleMetadataEmitter(
private val packageFqName: String
) : StubIrVisitor<StubContainer?, Unit> {
private val uniqIds = StubIrUniqIdProvider()
private val classes = mutableListOf<KmClass>()
private val properties = mutableListOf<KmProperty>()
private val typeAliases = mutableListOf<KmTypeAlias>()
private val functions = mutableListOf<KmFunction>()
fun writeModule(): KmModuleFragment = KmModuleFragment().also { km ->
km.fqName = packageFqName
km.classes += classes
km.pkg = writePackage()
}
private fun writePackage() = KmPackage().also { km ->
km.fqName = packageFqName
km.typeAliases += typeAliases
km.properties += properties
km.functions += functions
}
override fun visitClass(element: ClassStub, data: StubContainer?) {
// TODO("not implemented")
}
override fun visitTypealias(element: TypealiasStub, data: StubContainer?) {
KmTypeAlias(element.flags, element.alias.topLevelName).apply {
uniqId = uniqIds.uniqIdForTypeAlias(element)
underlyingType = element.aliasee.map(shouldExpandTypeAliases = false)
expandedType = element.aliasee.map()
}.let(typeAliases::add)
}
override fun visitFunction(element: FunctionStub, data: StubContainer?) {
KmFunction(element.flags, element.name).apply {
element.annotations.mapTo(annotations, AnnotationStub::map)
returnType = element.returnType.map()
element.parameters.mapTo(valueParameters, FunctionParameterStub::map)
element.typeParameters.mapTo(typeParameters, TypeParameterStub::map)
uniqId = uniqIds.uniqIdForFunction(element)
}.let(functions::add)
}
override fun visitProperty(element: PropertyStub, data: StubContainer?) {
KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).apply {
element.annotations.mapTo(annotations, AnnotationStub::map)
uniqId = uniqIds.uniqIdForProperty(element)
returnType = element.type.map()
if (element.kind is PropertyStub.Kind.Var) {
val setter = element.kind.setter
setter.annotations.mapTo(setterAnnotations, AnnotationStub::map)
// TODO: Maybe it's better to explicitly add setter parameter in stub.
setterParameter = FunctionParameterStub("value", element.type).map()
}
getterAnnotations += when (element.kind) {
is PropertyStub.Kind.Val -> element.kind.getter.annotations.map(AnnotationStub::map)
is PropertyStub.Kind.Var -> element.kind.getter.annotations.map(AnnotationStub::map)
is PropertyStub.Kind.Constant -> emptyList()
}
if (element.kind is PropertyStub.Kind.Constant) {
compileTimeValue = element.kind.constant.map()
}
}.let(properties::add)
}
override fun visitConstructor(constructorStub: ConstructorStub, data: StubContainer?) {
// TODO("not implemented")
}
override fun visitPropertyAccessor(propertyAccessor: PropertyAccessor, data: StubContainer?) {
// TODO("not implemented")
}
override fun visitSimpleStubContainer(simpleStubContainer: SimpleStubContainer, data: StubContainer?) {
simpleStubContainer.children.forEach { it.accept(this, simpleStubContainer) }
}
}
private val FunctionStub.flags: Flags
get() = listOfNotNull(
Flag.Common.IS_PUBLIC,
Flag.Function.IS_EXTERNAL,
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_FINAL.takeIf { modality == MemberStubModality.FINAL },
Flag.IS_OPEN.takeIf { modality == MemberStubModality.OPEN }
).let { flagsOf(*it.toTypedArray()) }
private val Classifier.fqNameSerialized: String
get() = buildString {
if (pkg.isNotEmpty()) {
append(pkg.replace('.', '/'))
append('/')
}
// Nested classes should dot-separated.
append(relativeFqName)
}
private val PropertyStub.flags: Flags
get() = listOfNotNull(
Flag.IS_PUBLIC,
Flag.Property.IS_DECLARATION,
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_FINAL.takeIf { modality == MemberStubModality.FINAL },
when (kind) {
is PropertyStub.Kind.Val -> null
is PropertyStub.Kind.Var -> Flag.Property.IS_VAR
is PropertyStub.Kind.Constant -> Flag.Property.IS_CONST
},
when (kind) {
is PropertyStub.Kind.Constant -> null
is PropertyStub.Kind.Val,
is PropertyStub.Kind.Var -> Flag.Property.HAS_GETTER
},
when (kind) {
is PropertyStub.Kind.Constant -> null
is PropertyStub.Kind.Val -> null
is PropertyStub.Kind.Var -> Flag.Property.HAS_SETTER
}
).let { flagsOf(*it.toTypedArray()) }
private val PropertyStub.getterFlags: Flags
get() = when (kind) {
is PropertyStub.Kind.Val -> kind.getter.flags
is PropertyStub.Kind.Var -> kind.getter.flags
is PropertyStub.Kind.Constant -> flagsOf()
}
private val PropertyAccessor.Getter.flags: Flags
get() = listOfNotNull(
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_PUBLIC,
Flag.IS_FINAL,
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Getter.ExternalGetter }
).let { flagsOf(*it.toTypedArray()) }
private val PropertyStub.setterFlags: Flags
get() = if (kind !is PropertyStub.Kind.Var) flagsOf()
else kind.setter.flags
private val PropertyAccessor.Setter.flags: Flags
get() = listOfNotNull(
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_PUBLIC,
Flag.IS_FINAL,
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Setter.ExternalSetter }
).let { flagsOf(*it.toTypedArray()) }
private val StubType.flags: Flags
get() = listOfNotNull(
Flag.Type.IS_NULLABLE.takeIf { nullable }
).let { flagsOf(*it.toTypedArray()) }
private val TypealiasStub.flags: Flags
get() = listOfNotNull(
Flag.IS_PUBLIC
).let { flagsOf(*it.toTypedArray()) }
private val FunctionParameterStub.flags: Flags
get() = listOfNotNull(
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }
).let { flagsOf(*it.toTypedArray()) }
private fun AnnotationStub.map(): KmAnnotation {
val args = when (this) {
AnnotationStub.ObjC.ConsumesReceiver -> TODO()
AnnotationStub.ObjC.ReturnsRetained -> TODO()
is AnnotationStub.ObjC.Method -> TODO()
is AnnotationStub.ObjC.Factory -> TODO()
AnnotationStub.ObjC.Consumed -> TODO()
is AnnotationStub.ObjC.Constructor -> TODO()
is AnnotationStub.ObjC.ExternalClass -> TODO()
AnnotationStub.CCall.CString -> mapOf()
AnnotationStub.CCall.WCString -> mapOf()
is AnnotationStub.CCall.Symbol ->
mapOf("id" to KmAnnotationArgument.StringValue(symbolName))
is AnnotationStub.CStruct -> TODO()
is AnnotationStub.CNaturalStruct -> TODO()
is AnnotationStub.CLength -> TODO()
is AnnotationStub.Deprecated -> TODO()
}
return KmAnnotation(classifier.fqNameSerialized, args)
}
/**
* @param shouldExpandTypeAliases describes how should we write type aliases.
* If [shouldExpandTypeAliases] is true then type alias-based types are written as
* ```
* Type {
* abbreviatedType = AbbreviatedType.abbreviatedClassifier
* classifier = AbbreviatedType.underlyingType
* arguments = AbbreviatedType.underlyingType.typeArguments
* }
* ```
* So we basically replacing type alias with underlying class.
* Otherwise:
* ```
* Type {
* classifier = AbbreviatedType.abbreviatedClassifier
* }
* ```
* As of 25 Nov 2019, the latter form is used only for KmTypeAlias.underlyingType.
*/
// TODO: Add caching if needed.
private fun StubType.map(shouldExpandTypeAliases: Boolean = true): KmType = when (this) {
is AbbreviatedType -> {
val typeAliasClassifier = KmClassifier.TypeAlias(abbreviatedClassifier.fqNameSerialized)
if (shouldExpandTypeAliases) {
// Abbreviated and expanded types have the same nullability.
KmType(flags).also { km ->
km.abbreviatedType = KmType(flags).also { it.classifier = typeAliasClassifier }
val kmUnderlyingType = underlyingType.map(true)
km.arguments += kmUnderlyingType.arguments
km.classifier = kmUnderlyingType.classifier
}
} else {
KmType(flags).also { km -> km.classifier = typeAliasClassifier }
}
}
is ClassifierStubType -> KmType(flags).also { km ->
typeArguments.mapTo(km.arguments) { it.map(shouldExpandTypeAliases) }
km.classifier = KmClassifier.Class(classifier.fqNameSerialized)
}
is FunctionalType -> KmType(flags).also { km ->
typeArguments.mapTo(km.arguments) { it.map(shouldExpandTypeAliases) }
km.classifier = KmClassifier.Class(classifier.fqNameSerialized)
}
is TypeParameterType -> KmType(flags).also { km ->
km.classifier = KmClassifier.TypeParameter(id)
}
}
private fun FunctionParameterStub.map(): KmValueParameter =
KmValueParameter(flags, name).also { km ->
val kmType = type.map()
if (isVararg) {
km.varargElementType = kmType
} else {
km.type = kmType
}
annotations.mapTo(km.annotations, AnnotationStub::map)
}
private fun TypeParameterStub.map(): KmTypeParameter =
KmTypeParameter(flagsOf(), name, id, KmVariance.INVARIANT).also { km ->
km.upperBounds.addIfNotNull(upperBound?.map())
}
private fun TypeArgument.map(expanded: Boolean=true): KmTypeProjection = when (this) {
TypeArgument.StarProjection -> KmTypeProjection.STAR
is TypeArgumentStub -> KmTypeProjection(variance.map(), type.map(expanded))
else -> error("Unexpected TypeArgument: $this")
}
private fun TypeArgument.Variance.map(): KmVariance = when (this) {
TypeArgument.Variance.INVARIANT -> KmVariance.INVARIANT
TypeArgument.Variance.IN -> KmVariance.IN
TypeArgument.Variance.OUT -> KmVariance.OUT
}
private fun ConstantStub.map(): KmAnnotationArgument<*> = when (this) {
is StringConstantStub -> KmAnnotationArgument.StringValue(value)
is IntegralConstantStub -> when (size) {
1 -> if (isSigned) {
KmAnnotationArgument.ByteValue(value.toByte())
} else {
KmAnnotationArgument.UByteValue(value.toByte())
}
2 -> if (isSigned) {
KmAnnotationArgument.ShortValue(value.toShort())
} else {
KmAnnotationArgument.UShortValue(value.toShort())
}
4 -> if (isSigned) {
KmAnnotationArgument.IntValue(value.toInt())
} else {
KmAnnotationArgument.UIntValue(value.toInt())
}
8 -> if (isSigned) {
KmAnnotationArgument.LongValue(value)
} else {
KmAnnotationArgument.ULongValue(value)
}
else -> error("Integral constant of value $value with unexpected size of $size.")
}
is DoubleConstantStub -> when (size) {
4 -> KmAnnotationArgument.FloatValue(value.toFloat())
8 -> KmAnnotationArgument.DoubleValue(value)
else -> error("Floating-point constant of value $value with unexpected size of $size.")
}
}
private val TypeParameterType.id: Int
get() = TODO()
private val TypeParameterStub.id: Int
get() = TODO()
@@ -29,19 +29,9 @@ class StubIrTextEmitter(
private val pkgName: String
get() = context.configuration.pkgName
private val jvmFileClassName = if (pkgName.isEmpty()) {
context.libName
} else {
pkgName.substringAfterLast('.')
}
private val StubContainer.isTopLevelContainer: Boolean
get() = this == builderResult.stubs
companion object {
private val VALID_PACKAGE_NAME_REGEX = "[a-zA-Z0-9_.]+".toRegex()
}
/**
* The output currently used by the generator.
* Should append line separator after any usage.
@@ -97,7 +87,7 @@ class StubIrTextEmitter(
private fun emitKotlinFileHeader() {
if (context.platform == KotlinPlatform.JVM) {
out("@file:JvmName(${jvmFileClassName.quoteAsKotlinLiteral()})")
out("@file:JvmName(${context.jvmFileClassName.quoteAsKotlinLiteral()})")
}
if (context.platform == KotlinPlatform.NATIVE) {
out("@file:kotlinx.cinterop.InteropStubs")
@@ -124,14 +114,7 @@ class StubIrTextEmitter(
out("@file:Suppress(${suppress.joinToString { it.quoteAsKotlinLiteral() }})")
if (pkgName != "") {
val packageName = pkgName.split(".").joinToString("."){
if(it.matches(VALID_PACKAGE_NAME_REGEX)){
it
}else{
"`$it`"
}
}
out("package $packageName")
out("package ${context.validPackageName}")
out("")
}
if (context.platform == KotlinPlatform.NATIVE) {
@@ -462,6 +445,11 @@ class StubIrTextEmitter(
if (stubType.nullable) append(")?")
}
is TypeParameterType -> "${stubType.name}$nullable"
is AbbreviatedType -> {
val classifier = kotlinFile.reference(stubType.abbreviatedClassifier)
val typeArguments = renderTypeArguments(stubType.typeArguments)
"$classifier$typeArguments$nullable"
}
}
}
@@ -5,34 +5,44 @@
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
sealed class StubType {
abstract val nullable: Boolean
abstract val typeArguments: List<TypeArgument>
}
/**
* Wrapper over [Classifier].
* @property underlyingType is not null if this type is an typealias.
*/
class ClassifierStubType(
val classifier: Classifier,
val typeArguments: List<TypeArgument> = emptyList(),
val underlyingType: StubType? = null,
override val typeArguments: List<TypeArgument> = emptyList(),
override val nullable: Boolean = false
) : StubType() {
fun nested(name: String): ClassifierStubType {
assert(underlyingType == null) {
"Cannot access nested class `$name` of typealias ${classifier.fqName}"
}
return ClassifierStubType(classifier.nested(name))
}
fun nested(name: String): ClassifierStubType =
ClassifierStubType(classifier.nested(name))
override fun toString(): String =
"${classifier.topLevelName}${typeArguments.ifNotEmpty { joinToString(prefix = "<", postfix = ">") } ?: ""}"
}
class AbbreviatedType(
val underlyingType: StubType,
val abbreviatedClassifier: Classifier,
override val typeArguments: List<TypeArgument>,
override val nullable: Boolean = false
) : StubType() {
override fun toString(): String =
"${abbreviatedClassifier.topLevelName}${typeArguments.ifNotEmpty { joinToString(prefix = "<", postfix = ">") } ?: ""}"
}
/**
* @return type from kotlinx.cinterop package
*/
fun KotlinPlatform.getRuntimeType(name: String, nullable: Boolean = false): StubType {
val classifier = Classifier.topLevel("kotlinx.cinterop", name)
val classifier = Classifier.topLevel(cinteropPackage, name)
PredefinedTypesHandler.tryExpandPlatformDependentTypealias(classifier, this, nullable)?.let { return it }
return ClassifierStubType(classifier, nullable = nullable)
}
@@ -41,18 +51,24 @@ fun KotlinPlatform.getRuntimeType(name: String, nullable: Boolean = false): Stub
* Functional type from kotlin package: ([parameterTypes]) -> [returnType]
*/
class FunctionalType(
val parameterTypes: List<StubType>,
val parameterTypes: List<StubType>, // TODO: Use TypeArguments.
val returnType: StubType,
override val nullable: Boolean = false
) : StubType() {
val classifier: Classifier =
Classifier.topLevel("kotlin", "Function${parameterTypes.size}")
override val typeArguments: List<TypeArgument> by lazy {
listOf(*parameterTypes.toTypedArray(), returnType).map { TypeArgumentStub(it) }
}
}
class TypeParameterType(
val name: String,
override val nullable: Boolean
) : StubType()
) : StubType() {
override val typeArguments: List<TypeArgument> = emptyList()
}
fun KotlinType.toStubIrType(): StubType = when (this) {
is KotlinFunctionType -> this.toStubIrType()
@@ -61,13 +77,16 @@ fun KotlinType.toStubIrType(): StubType = when (this) {
}
private fun KotlinFunctionType.toStubIrType(): StubType =
FunctionalType(parameterTypes.map { it.toStubIrType() }, returnType.toStubIrType(), nullable)
FunctionalType(parameterTypes.map(KotlinType::toStubIrType), returnType.toStubIrType(), nullable)
private fun KotlinClassifierType.toStubIrType(): StubType {
PredefinedTypesHandler.tryExpandPredefinedTypealias(classifier, nullable)?.let { return it }
val typeArguments = arguments.map { it.toStubIrType() }
val underlyingType = underlyingType?.toStubIrType()
return ClassifierStubType(classifier, typeArguments, underlyingType, nullable)
val typeArguments = arguments.map(KotlinTypeArgument::toStubIrType)
PredefinedTypesHandler.tryExpandPredefinedTypealias(classifier, nullable, typeArguments)?.let { return it }
return if (underlyingType == null) {
ClassifierStubType(classifier, typeArguments, nullable)
} else {
AbbreviatedType(underlyingType.toStubIrType(), classifier, typeArguments, nullable)
}
}
private fun KotlinTypeArgument.toStubIrType(): TypeArgument = when (this) {
@@ -114,53 +133,60 @@ private object PredefinedTypesHandler {
return ClassifierStubType(classifier, listOf(TypeArgumentStub(primitiveType.toStubIrType())), nullable = nullable)
}
private fun expandCOpaquePointerVar(nullable: Boolean): ClassifierStubType {
private fun expandCOpaquePointerVar(nullable: Boolean): AbbreviatedType {
val typeArgument = TypeArgumentStub(expandCOpaquePointer(nullable=false))
val underlyingType = ClassifierStubType(
KotlinTypes.cPointerVarOf, listOf(typeArgument), nullable = nullable
)
return ClassifierStubType(
KotlinTypes.cOpaquePointerVar.classifier, underlyingType = underlyingType, nullable = nullable
)
return AbbreviatedType(underlyingType, KotlinTypes.cOpaquePointerVar.classifier, emptyList(), nullable)
}
private fun expandCOpaquePointer(nullable: Boolean): ClassifierStubType {
private fun expandCOpaquePointer(nullable: Boolean): AbbreviatedType {
val typeArgument = TypeArgumentStub(ClassifierStubType(KotlinTypes.cPointed), TypeArgument.Variance.OUT)
val underlyingType = ClassifierStubType(
KotlinTypes.cPointer, listOf(typeArgument), nullable = nullable
)
return ClassifierStubType(
KotlinTypes.cOpaquePointer.classifier, underlyingType = underlyingType, nullable = nullable
return AbbreviatedType(underlyingType, KotlinTypes.cOpaquePointer.classifier, emptyList(), nullable)
}
private fun expandCPointerVar(typeArguments: List<TypeArgument>, nullable: Boolean): AbbreviatedType {
require(typeArguments.size == 1) { "CPointerVar has only one type argument." }
val cPointer = ClassifierStubType(KotlinTypes.cPointer, typeArguments)
val cPointerVarOfTypeArgument = TypeArgumentStub(cPointer)
val underlyingType = ClassifierStubType(
KotlinTypes.cPointerVarOf, listOf(cPointerVarOfTypeArgument), nullable = nullable
)
return AbbreviatedType(underlyingType, KotlinTypes.cPointerVar, typeArguments, nullable)
}
/**
* @param primitiveVarType one of kotlinx.cinterop.{primitive}Var types.
* @return typealias in terms of StubIR types.
*/
private fun expandPrimitiveVarType(primitiveVarClassifier: Classifier, nullable: Boolean): ClassifierStubType {
private fun expandPrimitiveVarType(primitiveVarClassifier: Classifier, nullable: Boolean): AbbreviatedType {
val primitiveType = primitiveVarClassifierToPrimitiveType.getValue(primitiveVarClassifier)
val underlyingType = getVarOfTypeFor(primitiveType, nullable)
return ClassifierStubType(primitiveVarClassifier, underlyingType = underlyingType, nullable = nullable)
return AbbreviatedType(underlyingType, primitiveVarClassifier, listOf(), nullable)
}
private fun expandNativePtr(platform: KotlinPlatform, nullable: Boolean): ClassifierStubType {
private fun expandNativePtr(platform: KotlinPlatform, nullable: Boolean): StubType {
val underlyingTypeClassifier = when (platform) {
KotlinPlatform.JVM -> KotlinTypes.long.classifier
KotlinPlatform.NATIVE -> Classifier.topLevel("kotlin.native.internal", "NativePtr")
}
val underlyingType = ClassifierStubType(underlyingTypeClassifier, nullable = nullable)
return ClassifierStubType(nativePtrClassifier, underlyingType = underlyingType, nullable = nullable)
return AbbreviatedType(underlyingType, nativePtrClassifier, listOf(), nullable)
}
/**
* @return [ClassifierStubType] if [classifier] is a typealias from [kotlinx.cinterop] package.
*/
fun tryExpandPredefinedTypealias(classifier: Classifier, nullable: Boolean): ClassifierStubType? =
fun tryExpandPredefinedTypealias(classifier: Classifier, nullable: Boolean, typeArguments: List<TypeArgument>): AbbreviatedType? =
when (classifier) {
in primitiveVarClassifierToPrimitiveType.keys -> expandPrimitiveVarType(classifier, nullable)
KotlinTypes.cOpaquePointer.classifier -> expandCOpaquePointer(nullable)
KotlinTypes.cOpaquePointerVar.classifier -> expandCOpaquePointerVar(nullable)
KotlinTypes.cPointerVar -> expandCPointerVar(typeArguments, nullable)
else -> null
}
@@ -169,9 +195,9 @@ private object PredefinedTypesHandler {
*/
fun tryExpandPlatformDependentTypealias(
classifier: Classifier, platform: KotlinPlatform, nullable: Boolean
): ClassifierStubType? =
): StubType? =
when (classifier) {
nativePtrClassifier -> expandNativePtr(platform, nullable)
else -> null
}
}
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import kotlinx.metadata.klib.UniqId
import org.jetbrains.kotlin.backend.common.serialization.cityHash64
internal class StubIrUniqIdProvider {
private val mangler = KotlinLikeInteropMangler()
fun uniqIdForFunction(function: FunctionStub): UniqId = with(mangler) {
when (function.origin) {
is StubOrigin.Function -> function.origin.function.uniqueSymbolName
is StubOrigin.ObjCMethod -> {
require(this.context is ManglingContext.Entity) {
"Unexpected mangling context $context for method ${function.name}."
}
function.origin.method.uniqueSymbolName
}
// TODO: What to do with "create" method in Objective-C categories?
else -> error("Unexpected origin ${function.origin} for function ${function.name}.")
}.toUniqId()
}
fun uniqIdForProperty(property: PropertyStub): UniqId = with (mangler) {
when (property.origin) {
is StubOrigin.ObjCProperty -> {
require(this.context is ManglingContext.Entity) {
"Unexpected mangling context $context for property ${property.name}."
}
property.origin.property.uniqueSymbolName
}
is StubOrigin.Constant -> property.origin.constantDef.uniqueSymbolName
is StubOrigin.Global -> property.origin.global.uniqueSymbolName
// TODO: What to do with origin for enum entries and struct fields?
else -> error("Unexpected origin ${property.origin} for property ${property.name}.")
}.toUniqId()
}
private fun InteropMangler.uniqSymbolNameForTypeAlias(origin: StubOrigin): String? = when (origin) {
is StubOrigin.TypeDef -> origin.typedefDef.uniqueSymbolName
is StubOrigin.Enum -> origin.enum.uniqueSymbolName
is StubOrigin.VarOf -> uniqSymbolNameForTypeAlias(origin.typeOrigin)?.let { "$it#Var" }
else -> null
}
fun uniqIdForTypeAlias(typeAlias: TypealiasStub): UniqId = with (mangler) {
uniqSymbolNameForTypeAlias(typeAlias.origin)
?: error("Unexpected origin ${typeAlias.origin} for typealias ${typeAlias.alias.fqName}.")
}.toUniqId()
private fun String.toUniqId() = UniqId(cityHash64())
}