diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CWrapperGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CWrapperGenerator.kt index 5bd8a8f2fa5..933133b21ad 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CWrapperGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CWrapperGenerator.kt @@ -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 diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt index 97c86a1607c..376bde30cf7 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt @@ -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, - 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( diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt index 1e0ba7853e1..cf7afb8642c 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt @@ -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 + ) } } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt index a727be493b3..4e7e660d0cc 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt @@ -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 { @@ -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)) } } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt index 92035bc83e1..c2faf92e124 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt @@ -45,11 +45,6 @@ class SimpleStubContainer( val StubContainer.children: List get() = (classes as List) + 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 = 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 = emptyList() } - class InterpretPointed(val cGlobalName:String, pointedType: WrapperStubType) : Getter() { + class InterpretPointed(val cGlobalName:String, pointedType: StubType) : Getter() { override val annotations: List = emptyList() val typeParameters: List = listOf(pointedType) } @@ -416,7 +391,7 @@ class EnumEntryStub( } class TypealiasStub( - val alias: ClassifierStubType, + val alias: Classifier, val aliasee: StubType ) : StubIrElement { diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBridgeBuilder.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBridgeBuilder.kt index fd75d03c1b9..5e4bcabc8c4 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBridgeBuilder.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBridgeBuilder.kt @@ -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." } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt index 62cd39d9b3f..f6532cd0128 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt @@ -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 = 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 @@ -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())) } } } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt index 9b5d100a59d..e1f5a84d1c9 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt @@ -42,8 +42,8 @@ fun StubContainer.computeNamesToBeDeclared(pkgName: String): List { }.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) } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt index 5e4eec8edad..c167e1277e7 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt @@ -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) = if (typeArguments.isNotEmpty()) { - typeArguments.joinToString(", ", "<", ">") { renderStubType(it.type) } + private fun renderTypeArguments(typeArguments: List) = 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) = if (typeParameters.isNotEmpty()) { typeParameters.joinToString(", ", " <", ">") { renderTypeParameter(it) } } else { diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt new file mode 100644 index 00000000000..15f73288b54 --- /dev/null +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt @@ -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 = 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, + 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. + */ +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 = + 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 + } +} \ No newline at end of file