[StubIR][Interop] Rework StubIR type system to make it usable for metadata-based interop
This commit is contained in:
committed by
Sergey Bogolepov
parent
bd0e0dd2e7
commit
303f6638f4
+4
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.native.interop.indexer.FunctionDecl
|
||||
|
||||
+11
-4
@@ -78,10 +78,13 @@ data class Classifier(
|
||||
}
|
||||
|
||||
val Classifier.type
|
||||
get() = KotlinClassifierType(this, arguments = emptyList(), nullable = false)
|
||||
get() = KotlinClassifierType(this, arguments = emptyList(), nullable = false, underlyingType = null)
|
||||
|
||||
fun Classifier.typeWith(vararg arguments: KotlinTypeArgument) =
|
||||
KotlinClassifierType(this, arguments.toList(), nullable = false)
|
||||
KotlinClassifierType(this, arguments.toList(), nullable = false, underlyingType = null)
|
||||
|
||||
fun Classifier.typeAbbreviation(expandedType: KotlinType) =
|
||||
KotlinClassifierType(this, arguments = emptyList(), nullable = false, underlyingType = expandedType)
|
||||
|
||||
interface KotlinTypeArgument {
|
||||
/**
|
||||
@@ -99,10 +102,14 @@ interface KotlinType : KotlinTypeArgument {
|
||||
fun makeNullableAsSpecified(nullable: Boolean): KotlinType
|
||||
}
|
||||
|
||||
/**
|
||||
* @property underlyingType is non-null if this type is an alias to another type.
|
||||
*/
|
||||
data class KotlinClassifierType(
|
||||
override val classifier: Classifier,
|
||||
val arguments: List<KotlinTypeArgument>,
|
||||
val nullable: Boolean
|
||||
val nullable: Boolean,
|
||||
val underlyingType: KotlinType?
|
||||
) : KotlinType {
|
||||
|
||||
override fun makeNullableAsSpecified(nullable: Boolean) = if (this.nullable == nullable) {
|
||||
@@ -195,6 +202,7 @@ object KotlinTypes {
|
||||
|
||||
val cValuesRef by InteropClassifier
|
||||
|
||||
val cPointed by InteropClassifier
|
||||
val cPointer by InteropClassifier
|
||||
val cPointerVar by InteropClassifier
|
||||
val cArrayPointer by InteropClassifier
|
||||
@@ -225,7 +233,6 @@ object KotlinTypes {
|
||||
|
||||
private object InteropClassifier : ClassifierAtPackage("kotlinx.cinterop")
|
||||
private object InteropType : TypeAtPackage("kotlinx.cinterop")
|
||||
|
||||
}
|
||||
|
||||
abstract class KotlinFile(
|
||||
|
||||
+8
-5
@@ -411,9 +411,9 @@ fun mirror(declarationMapper: DeclarationMapper, type: Type): TypeMirror = when
|
||||
!type.def.isAnonymous -> {
|
||||
val baseTypeMirror = mirror(declarationMapper, type.def.baseType)
|
||||
TypeMirror.ByValue(
|
||||
Classifier.topLevel(pkg, kotlinName + "Var").type,
|
||||
Classifier.topLevel(pkg, kotlinName + "Var").typeAbbreviation(baseTypeMirror.pointedType),
|
||||
baseTypeMirror.info,
|
||||
Classifier.topLevel(pkg, kotlinName).type
|
||||
Classifier.topLevel(pkg, kotlinName).typeAbbreviation(baseTypeMirror.argType)
|
||||
)
|
||||
}
|
||||
else -> mirror(declarationMapper, type.def.baseType)
|
||||
@@ -463,13 +463,16 @@ fun mirror(declarationMapper: DeclarationMapper, type: Type): TypeMirror = when
|
||||
val name = type.def.name
|
||||
when (baseType) {
|
||||
is TypeMirror.ByValue -> TypeMirror.ByValue(
|
||||
Classifier.topLevel(pkg, "${name}Var").type,
|
||||
Classifier.topLevel(pkg, "${name}Var").typeAbbreviation(baseType.pointedType),
|
||||
baseType.info,
|
||||
Classifier.topLevel(pkg, name).type,
|
||||
Classifier.topLevel(pkg, name).typeAbbreviation(baseType.valueType),
|
||||
nullable = baseType.nullable
|
||||
)
|
||||
|
||||
is TypeMirror.ByRef -> TypeMirror.ByRef(Classifier.topLevel(pkg, name).type, baseType.info)
|
||||
is TypeMirror.ByRef -> TypeMirror.ByRef(
|
||||
Classifier.topLevel(pkg, name).typeAbbreviation(baseType.pointedType),
|
||||
baseType.info
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-14
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.native.interop.gen
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.native.interop.indexer.*
|
||||
|
||||
internal fun ObjCMethod.getKotlinParameterNames(forConstructorOrFactory: Boolean = false): List<String> {
|
||||
@@ -71,7 +70,7 @@ private fun ObjCMethod.getKotlinParameters(
|
||||
if (this.isInit && this.parameters.isEmpty() && this.selector != "init") {
|
||||
// Create synthetic Unit parameter, just like Swift does in this case:
|
||||
val parameterName = this.selector.removePrefix("init").removePrefix("With").decapitalize()
|
||||
return listOf(FunctionParameterStub(parameterName, WrapperStubType(KotlinTypes.unit)))
|
||||
return listOf(FunctionParameterStub(parameterName, KotlinTypes.unit.toStubIrType()))
|
||||
// Note: this parameter is explicitly handled in compiler.
|
||||
}
|
||||
|
||||
@@ -82,12 +81,12 @@ private fun ObjCMethod.getKotlinParameters(
|
||||
val kotlinType = stubIrBuilder.mirror(it.type).argType
|
||||
val name = names[index]
|
||||
val annotations = if (it.nsConsumed) listOf(AnnotationStub.ObjC.Consumed) else emptyList()
|
||||
FunctionParameterStub(name, WrapperStubType(kotlinType), isVararg = false, annotations = annotations)
|
||||
FunctionParameterStub(name, kotlinType.toStubIrType(), isVararg = false, annotations = annotations)
|
||||
}
|
||||
if (this.isVariadic) {
|
||||
result += FunctionParameterStub(
|
||||
names.last(),
|
||||
WrapperStubType(KotlinTypes.any.makeNullable()),
|
||||
KotlinTypes.any.makeNullable().toStubIrType(),
|
||||
isVararg = true,
|
||||
annotations = emptyList()
|
||||
)
|
||||
@@ -115,10 +114,10 @@ private class ObjCMethodStubBuilder(
|
||||
val returnType = method.getReturnType(container.classOrProtocol)
|
||||
isStret = returnType.isStret(context.configuration.target)
|
||||
stubReturnType = if (returnType.unwrapTypedefs() is VoidType) {
|
||||
WrapperStubType(KotlinTypes.unit)
|
||||
KotlinTypes.unit
|
||||
} else {
|
||||
WrapperStubType(context.mirror(returnType).argType)
|
||||
}
|
||||
context.mirror(returnType).argType
|
||||
}.toStubIrType()
|
||||
val methodAnnotation = AnnotationStub.ObjC.Method(
|
||||
method.selector,
|
||||
method.encoding,
|
||||
@@ -190,7 +189,7 @@ private class ObjCMethodStubBuilder(
|
||||
val annotations = buildObjCMethodAnnotations(factoryAnnotation)
|
||||
|
||||
val originalReturnType = method.getReturnType(container.clazz)
|
||||
val typeParameter = TypeParameterStub("T", WrapperStubType(clazz))
|
||||
val typeParameter = TypeParameterStub("T", clazz.toStubIrType())
|
||||
val returnType = if (originalReturnType is ObjCPointer) {
|
||||
typeParameter.getStubType(originalReturnType.isNullable)
|
||||
} else {
|
||||
@@ -414,19 +413,19 @@ internal abstract class ObjCContainerStubBuilder(
|
||||
} else {
|
||||
if (isMeta) KotlinTypes.objCObjectBaseMeta else KotlinTypes.objCObjectBase
|
||||
}
|
||||
interfaces += WrapperStubType(baseClassifier.type)
|
||||
interfaces += baseClassifier.type.toStubIrType()
|
||||
}
|
||||
container.protocols.forEach {
|
||||
interfaces += WrapperStubType(context.getKotlinClassFor(it, isMeta).type)
|
||||
interfaces += context.getKotlinClassFor(it, isMeta).type.toStubIrType()
|
||||
}
|
||||
if (interfaces.isEmpty()) {
|
||||
assert(container is ObjCProtocol)
|
||||
val classifier = if (isMeta) KotlinTypes.objCObjectMeta else KotlinTypes.objCObject
|
||||
interfaces += WrapperStubType(classifier.type)
|
||||
interfaces += classifier.type.toStubIrType()
|
||||
}
|
||||
if (!isMeta && container.isProtocolClass()) {
|
||||
// TODO: map Protocol type to ObjCProtocol instead.
|
||||
interfaces += WrapperStubType(KotlinTypes.objCProtocol.type)
|
||||
interfaces += KotlinTypes.objCProtocol.type.toStubIrType()
|
||||
}
|
||||
interfaces
|
||||
}
|
||||
@@ -491,7 +490,7 @@ internal class ObjCClassStubBuilder(
|
||||
|
||||
val objCClassType = KotlinTypes.objCClassOf.typeWith(
|
||||
context.getKotlinClassFor(clazz, isMeta = false).type
|
||||
).let { WrapperStubType(it) }
|
||||
).toStubIrType()
|
||||
|
||||
val superClassInit = SuperClassInit(companionSuper)
|
||||
val companion = ClassStub.Companion(superClassInit, listOf(objCClassType))
|
||||
@@ -575,7 +574,7 @@ private class ObjCPropertyStubBuilder(
|
||||
is ObjCClassOrProtocol -> null
|
||||
is ObjCCategory -> ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass))
|
||||
}
|
||||
return listOf(PropertyStub(property.name, WrapperStubType(kotlinType), kind, modality, receiver))
|
||||
return listOf(PropertyStub(property.name, kotlinType.toStubIrType(), kind, modality, receiver))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-40
@@ -45,11 +45,6 @@ class SimpleStubContainer(
|
||||
val StubContainer.children: List<StubIrElement>
|
||||
get() = (classes as List<StubIrElement>) + properties + functions + typealiases
|
||||
|
||||
|
||||
sealed class StubType {
|
||||
abstract val nullable: Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks that abstract value of such type can be passed as value.
|
||||
*/
|
||||
@@ -59,45 +54,25 @@ class TypeParameterStub(
|
||||
val name: String,
|
||||
val upperBound: StubType? = null
|
||||
) {
|
||||
fun getStubType(nullable: Boolean): StubType =
|
||||
SymbolicStubType(name, nullable = nullable)
|
||||
fun getStubType(nullable: Boolean) =
|
||||
TypeParameterType(name, nullable = nullable)
|
||||
|
||||
}
|
||||
|
||||
// Add variance if needed
|
||||
class TypeArgumentStub(val type: StubType)
|
||||
interface TypeArgument {
|
||||
object StarProjection : TypeArgument
|
||||
|
||||
/**
|
||||
* Wrapper over [KotlinType].
|
||||
*/
|
||||
class WrapperStubType(
|
||||
val kotlinType: KotlinType
|
||||
) : StubType() {
|
||||
override val nullable: Boolean
|
||||
get() = when (kotlinType) {
|
||||
is KotlinClassifierType -> kotlinType.nullable
|
||||
is KotlinFunctionType -> kotlinType.nullable
|
||||
else -> error("Unknown KotlinType: $kotlinType")
|
||||
}
|
||||
enum class Variance {
|
||||
INVARIANT,
|
||||
IN,
|
||||
OUT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper over [Classifier].
|
||||
*/
|
||||
class ClassifierStubType(
|
||||
val classifier: Classifier,
|
||||
val typeArguments: List<TypeArgumentStub> = emptyList(),
|
||||
override val nullable: Boolean = false
|
||||
) : StubType()
|
||||
|
||||
|
||||
/**
|
||||
* Fallback variant for all cases where we cannot refer to specific [KotlinType] or [Classifier].
|
||||
*/
|
||||
class SymbolicStubType(
|
||||
val name: String,
|
||||
override val nullable: Boolean = false
|
||||
) : StubType()
|
||||
class TypeArgumentStub(
|
||||
val type: StubType,
|
||||
val variance: TypeArgument.Variance = TypeArgument.Variance.INVARIANT
|
||||
) : TypeArgument
|
||||
|
||||
/**
|
||||
* Represents a source of StubIr element.
|
||||
@@ -344,7 +319,7 @@ sealed class PropertyAccessor : FunctionalStub {
|
||||
override val annotations: List<AnnotationStub> = emptyList()
|
||||
}
|
||||
|
||||
class InterpretPointed(val cGlobalName:String, pointedType: WrapperStubType) : Getter() {
|
||||
class InterpretPointed(val cGlobalName:String, pointedType: StubType) : Getter() {
|
||||
override val annotations: List<AnnotationStub> = emptyList()
|
||||
val typeParameters: List<StubType> = listOf(pointedType)
|
||||
}
|
||||
@@ -416,7 +391,7 @@ class EnumEntryStub(
|
||||
}
|
||||
|
||||
class TypealiasStub(
|
||||
val alias: ClassifierStubType,
|
||||
val alias: Classifier,
|
||||
val aliasee: StubType
|
||||
) : StubIrElement {
|
||||
|
||||
|
||||
+3
-5
@@ -239,11 +239,9 @@ class StubIrBridgeBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isCValuesRef(type: StubType): Boolean {
|
||||
if (type !is WrapperStubType) return false
|
||||
|
||||
return type.kotlinType is KotlinClassifierType && type.kotlinType.classifier == KotlinTypes.cValuesRef
|
||||
}
|
||||
private fun isCValuesRef(type: StubType): Boolean =
|
||||
(type as? ClassifierStubType)?.let { it.classifier == KotlinTypes.cValuesRef }
|
||||
?: false
|
||||
|
||||
private fun generateBridgeBody(function: FunctionStub) {
|
||||
assert(context.platform == KotlinPlatform.JVM) { "Function ${function.name} was not marked as external." }
|
||||
|
||||
+30
-30
@@ -16,7 +16,7 @@ internal class MacroConstantStubBuilder(
|
||||
val declaration = when (constant) {
|
||||
is IntegerConstantDef -> {
|
||||
val literal = context.tryCreateIntegralStub(constant.type, constant.value) ?: return emptyList()
|
||||
val kotlinType = WrapperStubType(context.mirror(constant.type).argType)
|
||||
val kotlinType = context.mirror(constant.type).argType.toStubIrType()
|
||||
when (context.platform) {
|
||||
KotlinPlatform.NATIVE -> PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Constant(literal))
|
||||
// No reason to make it const val with backing field on Kotlin/JVM yet:
|
||||
@@ -28,13 +28,13 @@ internal class MacroConstantStubBuilder(
|
||||
}
|
||||
is FloatingConstantDef -> {
|
||||
val literal = context.tryCreateDoubleStub(constant.type, constant.value) ?: return emptyList()
|
||||
val kotlinType = WrapperStubType(context.mirror(constant.type).argType)
|
||||
val kotlinType = context.mirror(constant.type).argType.toStubIrType()
|
||||
val getter = PropertyAccessor.Getter.SimpleGetter(constant = literal)
|
||||
PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Val(getter))
|
||||
}
|
||||
is StringConstantDef -> {
|
||||
val literal = StringConstantStub(constant.value.quoteAsKotlinLiteral())
|
||||
val kotlinType = WrapperStubType(KotlinTypes.string)
|
||||
val kotlinType = KotlinTypes.string.toStubIrType()
|
||||
val getter = PropertyAccessor.Getter.SimpleGetter(constant = literal)
|
||||
PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Val(getter))
|
||||
}
|
||||
@@ -83,16 +83,16 @@ internal class StructStubBuilder(
|
||||
}
|
||||
val kind = PropertyStub.Kind.Val(PropertyAccessor.Getter.ArrayMemberAt(offset))
|
||||
// TODO: Should receiver be added?
|
||||
PropertyStub(field.name, WrapperStubType(type), kind, annotations = annotations)
|
||||
PropertyStub(field.name, type.toStubIrType(), kind, annotations = annotations)
|
||||
} else {
|
||||
val pointedType = WrapperStubType(fieldRefType.pointedType)
|
||||
val pointedType = fieldRefType.pointedType.toStubIrType()
|
||||
val pointedTypeArgument = TypeArgumentStub(pointedType)
|
||||
if (fieldRefType is TypeMirror.ByValue) {
|
||||
val kind = PropertyStub.Kind.Var(
|
||||
PropertyAccessor.Getter.MemberAt(offset, typeArguments = listOf(pointedTypeArgument), hasValueAccessor = true),
|
||||
PropertyAccessor.Setter.MemberAt(offset, typeArguments = listOf(pointedTypeArgument))
|
||||
)
|
||||
PropertyStub(field.name, WrapperStubType(fieldRefType.argType), kind)
|
||||
PropertyStub(field.name, fieldRefType.argType.toStubIrType(), kind)
|
||||
} else {
|
||||
val kind = PropertyStub.Kind.Val(PropertyAccessor.Getter.MemberAt(offset, hasValueAccessor = false))
|
||||
PropertyStub(field.name, pointedType, kind)
|
||||
@@ -113,15 +113,15 @@ internal class StructStubBuilder(
|
||||
context.bridgeComponentsBuilder.getterToBridgeInfo[readBits] = BridgeGenerationInfo("", typeInfo)
|
||||
context.bridgeComponentsBuilder.setterToBridgeInfo[writeBits] = BridgeGenerationInfo("", typeInfo)
|
||||
val kind = PropertyStub.Kind.Var(readBits, writeBits)
|
||||
PropertyStub(field.name, WrapperStubType(kotlinType), kind)
|
||||
PropertyStub(field.name, kotlinType.toStubIrType(), kind)
|
||||
}
|
||||
|
||||
val superClass = SymbolicStubType("CStructVar")
|
||||
val rawPtrConstructorParam = ConstructorParameterStub("rawPtr", SymbolicStubType("NativePtr"))
|
||||
val superClass = context.platform.getRuntimeType("CStructVar")
|
||||
require(superClass is ClassifierStubType)
|
||||
val rawPtrConstructorParam = ConstructorParameterStub("rawPtr", context.platform.getRuntimeType("NativePtr"))
|
||||
val superClassInit = SuperClassInit(superClass, listOf(GetConstructorParameter(rawPtrConstructorParam)))
|
||||
|
||||
// TODO: How we will differ Type and CStructVar.Type?
|
||||
val companionSuper = SymbolicStubType("Type")
|
||||
val companionSuper = superClass.nested("Type")
|
||||
val typeSize = listOf(IntegralConstantStub(def.size, 4, true), IntegralConstantStub(def.align.toLong(), 4, true))
|
||||
val companionSuperInit = SuperClassInit(companionSuper, typeSize)
|
||||
val companion = ClassStub.Companion(companionSuperInit)
|
||||
@@ -170,8 +170,8 @@ internal class StructStubBuilder(
|
||||
private fun generateForwardStruct(s: StructDecl): List<StubIrElement> = when (context.platform) {
|
||||
KotlinPlatform.JVM -> {
|
||||
val classifier = context.getKotlinClassForPointed(s)
|
||||
val superClass = SymbolicStubType("COpaque")
|
||||
val rawPtrConstructorParam = ConstructorParameterStub("rawPtr", SymbolicStubType("NativePtr"))
|
||||
val superClass = context.platform.getRuntimeType("COpaque")
|
||||
val rawPtrConstructorParam = ConstructorParameterStub("rawPtr", context.platform.getRuntimeType("NativePtr"))
|
||||
val superClassInit = SuperClassInit(superClass, listOf(GetConstructorParameter(rawPtrConstructorParam)))
|
||||
val origin = StubOrigin.Struct(s)
|
||||
listOf(ClassStub.Simple(classifier, ClassStubModality.NONE, listOf(rawPtrConstructorParam), superClassInit, origin = origin))
|
||||
@@ -189,7 +189,7 @@ internal class EnumStubBuilder(
|
||||
return generateEnumAsConstants(enumDef)
|
||||
}
|
||||
val baseTypeMirror = context.mirror(enumDef.baseType)
|
||||
val baseType = WrapperStubType(baseTypeMirror.argType)
|
||||
val baseType = baseTypeMirror.argType.toStubIrType()
|
||||
|
||||
val clazz = (context.mirror(EnumType(enumDef)) as TypeMirror.ByValue).valueType.classifier
|
||||
val qualifier = ConstructorParameterStub.Qualifier.VAL(overrides = true)
|
||||
@@ -216,7 +216,7 @@ internal class EnumStubBuilder(
|
||||
val enum = ClassStub.Enum(clazz, canonicalEntries,
|
||||
origin = StubOrigin.Enum(enumDef),
|
||||
constructorParameters = listOf(valueParamStub),
|
||||
interfaces = listOf(SymbolicStubType("CEnum"))
|
||||
interfaces = listOf(context.platform.getRuntimeType("CEnum"))
|
||||
)
|
||||
context.bridgeComponentsBuilder.enumToTypeMirror[enum] = baseTypeMirror
|
||||
|
||||
@@ -260,8 +260,8 @@ internal class EnumStubBuilder(
|
||||
val varTypeName = typeMirror.info.constructPointedType(typeMirror.valueType)
|
||||
val varTypeClassifier = typeMirror.pointedType.classifier
|
||||
val valueTypeClassifier = typeMirror.valueType.classifier
|
||||
typealiases += TypealiasStub(ClassifierStubType(varTypeClassifier), WrapperStubType(varTypeName))
|
||||
typealiases += TypealiasStub(ClassifierStubType(valueTypeClassifier), WrapperStubType(baseKotlinType))
|
||||
typealiases += TypealiasStub(varTypeClassifier, varTypeName.toStubIrType())
|
||||
typealiases += TypealiasStub(valueTypeClassifier, baseKotlinType.toStubIrType())
|
||||
|
||||
kotlinType = typeMirror.valueType
|
||||
StubContainerMeta()
|
||||
@@ -273,7 +273,7 @@ internal class EnumStubBuilder(
|
||||
val kind = PropertyStub.Kind.Val(getter)
|
||||
entries += PropertyStub(
|
||||
constant.name,
|
||||
WrapperStubType(kotlinType),
|
||||
kotlinType.toStubIrType(),
|
||||
kind,
|
||||
MemberStubModality.FINAL,
|
||||
null
|
||||
@@ -313,7 +313,7 @@ internal class FunctionStubBuilder(
|
||||
KotlinPlatform.JVM -> emptyList()
|
||||
KotlinPlatform.NATIVE -> listOf(AnnotationStub.CCall.CString)
|
||||
}
|
||||
val type = WrapperStubType(KotlinTypes.string.makeNullable())
|
||||
val type = KotlinTypes.string.makeNullable().toStubIrType()
|
||||
val functionParameterStub = FunctionParameterStub(parameterName, type, annotations, origin = origin)
|
||||
context.bridgeComponentsBuilder.cStringParameters += functionParameterStub
|
||||
functionParameterStub
|
||||
@@ -323,27 +323,27 @@ internal class FunctionStubBuilder(
|
||||
KotlinPlatform.JVM -> emptyList()
|
||||
KotlinPlatform.NATIVE -> listOf(AnnotationStub.CCall.WCString)
|
||||
}
|
||||
val type = WrapperStubType(KotlinTypes.string.makeNullable())
|
||||
val type = KotlinTypes.string.makeNullable().toStubIrType()
|
||||
val functionParameterStub = FunctionParameterStub(parameterName, type, annotations, origin = origin)
|
||||
context.bridgeComponentsBuilder.wCStringParameters += functionParameterStub
|
||||
functionParameterStub
|
||||
}
|
||||
representAsValuesRef != null -> {
|
||||
FunctionParameterStub(parameterName, WrapperStubType(representAsValuesRef), origin = origin)
|
||||
FunctionParameterStub(parameterName, representAsValuesRef.toStubIrType(), origin = origin)
|
||||
}
|
||||
else -> {
|
||||
val mirror = context.mirror(parameter.type)
|
||||
val type = WrapperStubType(mirror.argType)
|
||||
val type = mirror.argType.toStubIrType()
|
||||
FunctionParameterStub(parameterName, type, origin = origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val returnType = WrapperStubType(if (func.returnsVoid()) {
|
||||
val returnType = if (func.returnsVoid()) {
|
||||
KotlinTypes.unit
|
||||
} else {
|
||||
context.mirror(func.returnType).argType
|
||||
})
|
||||
}.toStubIrType()
|
||||
|
||||
|
||||
val annotations: List<AnnotationStub>
|
||||
@@ -353,7 +353,7 @@ internal class FunctionStubBuilder(
|
||||
mustBeExternal = false
|
||||
} else {
|
||||
if (func.isVararg) {
|
||||
val type = WrapperStubType(KotlinTypes.any.makeNullable())
|
||||
val type = KotlinTypes.any.makeNullable().toStubIrType()
|
||||
parameters += FunctionParameterStub("variadicArguments", type, isVararg = true)
|
||||
}
|
||||
annotations = listOf(AnnotationStub.CCall.Symbol("${context.generateNextUniqueId("knifunptr_")}_${func.name}"))
|
||||
@@ -485,12 +485,12 @@ internal class GlobalStubBuilder(
|
||||
}
|
||||
is TypeMirror.ByRef -> {
|
||||
kotlinType = mirror.pointedType
|
||||
val getter = PropertyAccessor.Getter.InterpretPointed(global.name, WrapperStubType(kotlinType))
|
||||
val getter = PropertyAccessor.Getter.InterpretPointed(global.name, kotlinType.toStubIrType())
|
||||
kind = PropertyStub.Kind.Val(getter)
|
||||
}
|
||||
}
|
||||
}
|
||||
return listOf(PropertyStub(global.name, WrapperStubType(kotlinType), kind))
|
||||
return listOf(PropertyStub(global.name, kotlinType.toStubIrType(), kind))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,13 +509,13 @@ internal class TypedefStubBuilder(
|
||||
val varTypeAliasee = mirror.info.constructPointedType(valueType)
|
||||
val valueTypeAliasee = baseMirror.valueType
|
||||
listOf(
|
||||
TypealiasStub(ClassifierStubType(varType), WrapperStubType(varTypeAliasee)),
|
||||
TypealiasStub(ClassifierStubType(valueType.classifier), WrapperStubType(valueTypeAliasee))
|
||||
TypealiasStub(varType, varTypeAliasee.toStubIrType()),
|
||||
TypealiasStub(valueType.classifier, valueTypeAliasee.toStubIrType())
|
||||
)
|
||||
}
|
||||
is TypeMirror.ByRef -> {
|
||||
val varTypeAliasee = baseMirror.pointedType
|
||||
listOf(TypealiasStub(ClassifierStubType(varType), WrapperStubType(varTypeAliasee)))
|
||||
listOf(TypealiasStub(varType, varTypeAliasee.toStubIrType()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -42,8 +42,8 @@ fun StubContainer.computeNamesToBeDeclared(pkgName: String): List<String> {
|
||||
}.onEach { checkPackageCorrectness(it) }.map { it.topLevelName }
|
||||
|
||||
val typealiasNames = typealiases
|
||||
.onEach { checkPackageCorrectness(it.alias.classifier) }
|
||||
.map { it.alias.classifier.topLevelName }
|
||||
.onEach { checkPackageCorrectness(it.alias) }
|
||||
.map { it.alias.topLevelName }
|
||||
|
||||
val namesFromNestedContainers = simpleContainers
|
||||
.flatMap { it.computeNamesToBeDeclared(pkgName) }
|
||||
|
||||
+36
-11
@@ -209,7 +209,7 @@ class StubIrTextEmitter(
|
||||
}
|
||||
|
||||
override fun visitTypealias(element: TypealiasStub, owner: StubContainer?) {
|
||||
val alias = renderClassifierDeclaration(element.alias.classifier) + renderTypeArguments(element.alias.typeArguments)
|
||||
val alias = renderClassifierDeclaration(element.alias)
|
||||
val aliasee = renderStubType(element.aliasee)
|
||||
out("typealias $alias = $aliasee")
|
||||
}
|
||||
@@ -464,15 +464,27 @@ class StubIrTextEmitter(
|
||||
return "${renderStubType(superClassInit.type)}$parameters"
|
||||
}
|
||||
|
||||
private fun renderStubType(stubType: StubType): String = when (stubType) {
|
||||
is WrapperStubType -> stubType.kotlinType.render(kotlinFile)
|
||||
is ClassifierStubType -> {
|
||||
val classifier = kotlinFile.reference(stubType.classifier)
|
||||
val typeArguments = renderTypeArguments(stubType.typeArguments)
|
||||
val nullability = if (stubType.nullable) "?" else ""
|
||||
"$classifier$typeArguments$nullability"
|
||||
private fun renderStubType(stubType: StubType): String {
|
||||
val nullable = if (stubType.nullable) "?" else ""
|
||||
|
||||
return when (stubType) {
|
||||
is ClassifierStubType -> {
|
||||
val classifier = kotlinFile.reference(stubType.classifier)
|
||||
val typeArguments = renderTypeArguments(stubType.typeArguments)
|
||||
"$classifier$typeArguments$nullable"
|
||||
}
|
||||
is FunctionalType -> buildString {
|
||||
if (stubType.nullable) append("(")
|
||||
|
||||
append('(')
|
||||
stubType.parameterTypes.joinTo(this) { renderStubType(it) }
|
||||
append(") -> ")
|
||||
append(renderStubType(stubType.returnType))
|
||||
|
||||
if (stubType.nullable) append(")?")
|
||||
}
|
||||
is TypeParameterType -> "${stubType.name}$nullable"
|
||||
}
|
||||
is SymbolicStubType -> stubType.name + if (stubType.nullable) "?" else ""
|
||||
}
|
||||
|
||||
private fun renderValueUsage(value: ValueStub): String = when (value) {
|
||||
@@ -647,12 +659,25 @@ class StubIrTextEmitter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderTypeArguments(typeArguments: List<TypeArgumentStub>) = if (typeArguments.isNotEmpty()) {
|
||||
typeArguments.joinToString(", ", "<", ">") { renderStubType(it.type) }
|
||||
private fun renderTypeArguments(typeArguments: List<TypeArgument>) = if (typeArguments.isNotEmpty()) {
|
||||
typeArguments.joinToString(", ", "<", ">") { renderTypeArgument(it) }
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
private fun renderTypeArgument(typeArgument: TypeArgument) = when (typeArgument) {
|
||||
is TypeArgumentStub -> {
|
||||
val variance = when (typeArgument.variance) {
|
||||
TypeArgument.Variance.INVARIANT -> ""
|
||||
TypeArgument.Variance.IN -> "in "
|
||||
TypeArgument.Variance.OUT -> "out "
|
||||
}
|
||||
"$variance${renderStubType(typeArgument.type)}"
|
||||
}
|
||||
TypeArgument.StarProjection -> "*"
|
||||
else -> error("Unexpected type argument: $typeArgument")
|
||||
}
|
||||
|
||||
private fun renderTypeParameters(typeParameters: List<TypeParameterStub>) = if (typeParameters.isNotEmpty()) {
|
||||
typeParameters.joinToString(", ", " <", ">") { renderTypeParameter(it) }
|
||||
} else {
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
|
||||
|
||||
sealed class StubType {
|
||||
abstract val nullable: Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return type from kotlinx.cinterop package
|
||||
*/
|
||||
fun KotlinPlatform.getRuntimeType(name: String, nullable: Boolean = false): StubType {
|
||||
val classifier = Classifier.topLevel("kotlinx.cinterop", name)
|
||||
PredefinedTypesHandler.tryExpandPlatformDependentTypealias(classifier, this, nullable)?.let { return it }
|
||||
return ClassifierStubType(classifier, nullable = nullable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional type from kotlin package: ([parameterTypes]) -> [returnType]
|
||||
*/
|
||||
class FunctionalType(
|
||||
val parameterTypes: List<StubType>,
|
||||
val returnType: StubType,
|
||||
override val nullable: Boolean = false
|
||||
) : StubType() {
|
||||
val classifier: Classifier =
|
||||
Classifier.topLevel("kotlin", "Function${parameterTypes.size}")
|
||||
}
|
||||
|
||||
class TypeParameterType(
|
||||
val name: String,
|
||||
override val nullable: Boolean
|
||||
) : StubType()
|
||||
|
||||
fun KotlinType.toStubIrType(): StubType = when (this) {
|
||||
is KotlinFunctionType -> this.toStubIrType()
|
||||
is KotlinClassifierType -> this.toStubIrType()
|
||||
else -> error("Unexpected KotlinType: $this")
|
||||
}
|
||||
|
||||
private fun KotlinFunctionType.toStubIrType(): StubType =
|
||||
FunctionalType(parameterTypes.map { it.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)
|
||||
}
|
||||
|
||||
private fun KotlinTypeArgument.toStubIrType(): TypeArgument = when (this) {
|
||||
is KotlinType -> TypeArgumentStub(this.toStubIrType())
|
||||
StarProjection -> TypeArgument.StarProjection
|
||||
else -> error("Unexpected KotlinTypeArgument: $this")
|
||||
}
|
||||
|
||||
/**
|
||||
* Types that come from kotlinx.cinterop require special handling because we
|
||||
* don't have explicit information about their structure.
|
||||
* For example, to be able to produce metadata-based interop library we need to know
|
||||
* that ByteVar is a typealias to ByteVarOf<Byte>.
|
||||
*/
|
||||
private object PredefinedTypesHandler {
|
||||
private const val cInteropPackage = "kotlinx.cinterop"
|
||||
|
||||
private val nativePtrClassifier = Classifier.topLevel(cInteropPackage, "NativePtr")
|
||||
|
||||
private val primitives = setOf(
|
||||
KotlinTypes.boolean,
|
||||
KotlinTypes.byte, KotlinTypes.short, KotlinTypes.int, KotlinTypes.long,
|
||||
KotlinTypes.uByte, KotlinTypes.uShort, KotlinTypes.uInt, KotlinTypes.uLong,
|
||||
KotlinTypes.float, KotlinTypes.double
|
||||
)
|
||||
|
||||
/**
|
||||
* kotlinx.cinterop.{primitive}Var -> kotlin.{primitive}
|
||||
*/
|
||||
private val primitiveVarClassifierToPrimitiveType: Map<Classifier, KotlinClassifierType> =
|
||||
primitives.associateBy {
|
||||
val typeVar = "${it.classifier.topLevelName}Var"
|
||||
Classifier.topLevel(cInteropPackage, typeVar)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param primitiveType primitive type from kotlin package.
|
||||
* @return kotlinx.cinterop.[primitiveType]VarOf<[primitiveType]>
|
||||
*/
|
||||
private fun getVarOfTypeFor(primitiveType: KotlinClassifierType, nullable: Boolean): ClassifierStubType {
|
||||
val typeVarOf = "${primitiveType.classifier.topLevelName}VarOf"
|
||||
val classifier = Classifier.topLevel(cInteropPackage, typeVarOf)
|
||||
return ClassifierStubType(classifier, listOf(TypeArgumentStub(primitiveType.toStubIrType())), nullable = nullable)
|
||||
}
|
||||
|
||||
private fun expandCOpaquePointerVar(nullable: Boolean): ClassifierStubType {
|
||||
val typeArgument = TypeArgumentStub(expandCOpaquePointer(nullable=false))
|
||||
val underlyingType = ClassifierStubType(
|
||||
KotlinTypes.cPointerVarOf, listOf(typeArgument), nullable = nullable
|
||||
)
|
||||
return ClassifierStubType(
|
||||
KotlinTypes.cOpaquePointerVar.classifier, underlyingType = underlyingType, nullable = nullable
|
||||
)
|
||||
}
|
||||
|
||||
private fun expandCOpaquePointer(nullable: Boolean): ClassifierStubType {
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param primitiveVarType one of kotlinx.cinterop.{primitive}Var types.
|
||||
* @return typealias in terms of StubIR types.
|
||||
*/
|
||||
private fun expandPrimitiveVarType(primitiveVarClassifier: Classifier, nullable: Boolean): ClassifierStubType {
|
||||
val primitiveType = primitiveVarClassifierToPrimitiveType.getValue(primitiveVarClassifier)
|
||||
val underlyingType = getVarOfTypeFor(primitiveType, nullable)
|
||||
return ClassifierStubType(primitiveVarClassifier, underlyingType = underlyingType, nullable = nullable)
|
||||
}
|
||||
|
||||
private fun expandNativePtr(platform: KotlinPlatform, nullable: Boolean): ClassifierStubType {
|
||||
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 [ClassifierStubType] if [classifier] is a typealias from [kotlinx.cinterop] package.
|
||||
*/
|
||||
fun tryExpandPredefinedTypealias(classifier: Classifier, nullable: Boolean): ClassifierStubType? =
|
||||
when (classifier) {
|
||||
in primitiveVarClassifierToPrimitiveType.keys -> expandPrimitiveVarType(classifier, nullable)
|
||||
KotlinTypes.cOpaquePointer.classifier -> expandCOpaquePointer(nullable)
|
||||
KotlinTypes.cOpaquePointerVar.classifier -> expandCOpaquePointerVar(nullable)
|
||||
else -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of [tryExpandPredefinedTypealias] with [platform]-dependent result.
|
||||
*/
|
||||
fun tryExpandPlatformDependentTypealias(
|
||||
classifier: Classifier, platform: KotlinPlatform, nullable: Boolean
|
||||
): ClassifierStubType? =
|
||||
when (classifier) {
|
||||
nativePtrClassifier -> expandNativePtr(platform, nullable)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user