[StubIr][Metadata] Add MappingExtensions class

Parent nodes may introduce some kind of context to their children. For example, type parameters.
Because of that we wrap all extension functions into MappingExtensions class.
This commit is contained in:
Sergey Bogolepov
2019-12-12 12:18:34 +07:00
committed by Sergey Bogolepov
parent 7e0a65e480
commit 37f9161ec2
3 changed files with 315 additions and 240 deletions
@@ -59,7 +59,7 @@ class TypeParameterStub(
val upperBound: StubType? = null val upperBound: StubType? = null
) { ) {
fun getStubType(nullable: Boolean) = fun getStubType(nullable: Boolean) =
TypeParameterType(name, nullable = nullable) TypeParameterType(name, nullable = nullable, typeParameterDeclaration = this)
} }
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.native.interop.gen
import kotlinx.metadata.* import kotlinx.metadata.*
import kotlinx.metadata.klib.* import kotlinx.metadata.klib.*
import org.jetbrains.kotlin.metadata.serialization.Interner
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
class StubIrMetadataEmitter( class StubIrMetadataEmitter(
@@ -69,7 +70,8 @@ internal class ModuleMetadataEmitter(
*/ */
private data class VisitingContext( private data class VisitingContext(
val container: StubContainer? = null, val container: StubContainer? = null,
val uniqIds: StubIrUniqIdProvider val uniqIds: StubIrUniqIdProvider,
val typeParametersInterner: Interner<TypeParameterStub> = Interner()
) )
private val visitor = object : StubIrVisitor<VisitingContext, Any> { private val visitor = object : StubIrVisitor<VisitingContext, Any> {
@@ -79,41 +81,47 @@ internal class ModuleMetadataEmitter(
} }
override fun visitTypealias(element: TypealiasStub, data: VisitingContext): KmTypeAlias = override fun visitTypealias(element: TypealiasStub, data: VisitingContext): KmTypeAlias =
with (MappingExtensions(data.typeParametersInterner)) {
KmTypeAlias(element.flags, element.alias.topLevelName).also { km -> KmTypeAlias(element.flags, element.alias.topLevelName).also { km ->
km.uniqId = data.uniqIds.uniqIdForTypeAlias(element) km.uniqId = data.uniqIds.uniqIdForTypeAlias(element)
km.underlyingType = element.aliasee.map(shouldExpandTypeAliases = false) km.underlyingType = element.aliasee.map(shouldExpandTypeAliases = false)
km.expandedType = element.aliasee.map() km.expandedType = element.aliasee.map()
} }
}
override fun visitFunction(element: FunctionStub, data: VisitingContext) = override fun visitFunction(element: FunctionStub, data: VisitingContext) =
with (MappingExtensions(data.typeParametersInterner)) {
KmFunction(element.flags, element.name).also { km -> KmFunction(element.flags, element.name).also { km ->
element.annotations.mapTo(km.annotations, AnnotationStub::map) element.typeParameters.mapTo(km.typeParameters) { it.map() }
element.parameters.mapTo(km.valueParameters) { it.map() }
element.annotations.mapTo(km.annotations) { it.map() }
km.returnType = element.returnType.map() km.returnType = element.returnType.map()
element.parameters.mapTo(km.valueParameters, FunctionParameterStub::map)
element.typeParameters.mapTo(km.typeParameters, TypeParameterStub::map)
km.uniqId = data.uniqIds.uniqIdForFunction(element) km.uniqId = data.uniqIds.uniqIdForFunction(element)
} }
}
override fun visitProperty(element: PropertyStub, data: VisitingContext) = override fun visitProperty(element: PropertyStub, data: VisitingContext) =
with (MappingExtensions(data.typeParametersInterner)) {
KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).also { km -> KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).also { km ->
element.annotations.mapTo(km.annotations, AnnotationStub::map) element.annotations.mapTo(km.annotations) { it.map() }
km.uniqId = data.uniqIds.uniqIdForProperty(element) km.uniqId = data.uniqIds.uniqIdForProperty(element)
km.returnType = element.type.map() km.returnType = element.type.map()
if (element.kind is PropertyStub.Kind.Var) { if (element.kind is PropertyStub.Kind.Var) {
val setter = element.kind.setter val setter = element.kind.setter
setter.annotations.mapTo(km.setterAnnotations, AnnotationStub::map) setter.annotations.mapTo(km.setterAnnotations) { it.map() }
// TODO: Maybe it's better to explicitly add setter parameter in stub. // TODO: Maybe it's better to explicitly add setter parameter in stub.
km.setterParameter = FunctionParameterStub("value", element.type).map() km.setterParameter = FunctionParameterStub("value", element.type).map()
} }
km.getterAnnotations += when (element.kind) { km.getterAnnotations += when (element.kind) {
is PropertyStub.Kind.Val -> element.kind.getter.annotations.map(AnnotationStub::map) is PropertyStub.Kind.Val -> element.kind.getter.annotations.map { it.map() }
is PropertyStub.Kind.Var -> element.kind.getter.annotations.map(AnnotationStub::map) is PropertyStub.Kind.Var -> element.kind.getter.annotations.map { it.map() }
is PropertyStub.Kind.Constant -> emptyList() is PropertyStub.Kind.Constant -> emptyList()
} }
if (element.kind is PropertyStub.Kind.Constant) { if (element.kind is PropertyStub.Kind.Constant) {
km.compileTimeValue = element.kind.constant.mapToAnnotationArgument() km.compileTimeValue = element.kind.constant.mapToAnnotationArgument()
} }
} }
}
override fun visitConstructor(constructorStub: ConstructorStub, data: VisitingContext) { override fun visitConstructor(constructorStub: ConstructorStub, data: VisitingContext) {
// TODO("not implemented") // TODO("not implemented")
@@ -129,17 +137,43 @@ internal class ModuleMetadataEmitter(
} }
} }
private val FunctionStub.flags: Flags /**
get() = listOfNotNull( * Collection of extension functions that simplify translation of
Flag.Common.IS_PUBLIC, * StubIr elements to Kotlin Metadata.
Flag.Function.IS_EXTERNAL, */
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }, private class MappingExtensions(
Flag.IS_FINAL.takeIf { modality == MemberStubModality.FINAL }, private val typeParametersInterner: Interner<TypeParameterStub>
Flag.IS_OPEN.takeIf { modality == MemberStubModality.OPEN }, ) {
Flag.IS_ABSTRACT.takeIf { modality == MemberStubModality.ABSTRACT }
).let { flagsOf(*it.toTypedArray()) }
private val Classifier.fqNameSerialized: String private fun flagsOfNotNull(vararg flags: Flag?): Flags =
flagsOf(*listOfNotNull(*flags).toTypedArray())
private fun <K, V> mapOfNotNull(vararg entries: Pair<K, V>?): Map<K, V> =
listOfNotNull(*entries).toMap()
private val VisibilityModifier.flags: Flags
get() = flagsOfNotNull(
Flag.IS_PUBLIC.takeIf { this == VisibilityModifier.PUBLIC },
Flag.IS_PROTECTED.takeIf { this == VisibilityModifier.PROTECTED },
Flag.IS_INTERNAL.takeIf { this == VisibilityModifier.INTERNAL },
Flag.IS_PRIVATE.takeIf { this == VisibilityModifier.PRIVATE }
)
private val MemberStubModality.flags: Flags
get() = flagsOfNotNull(
Flag.IS_FINAL.takeIf { this == MemberStubModality.FINAL },
Flag.IS_OPEN.takeIf { this == MemberStubModality.OPEN },
Flag.IS_ABSTRACT.takeIf { this == MemberStubModality.ABSTRACT }
)
val FunctionStub.flags: Flags
get() = flagsOfNotNull(
Flag.IS_PUBLIC,
Flag.Function.IS_EXTERNAL,
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }
) or modality.flags
val Classifier.fqNameSerialized: String
get() = buildString { get() = buildString {
if (pkg.isNotEmpty()) { if (pkg.isNotEmpty()) {
append(pkg.replace('.', '/')) append(pkg.replace('.', '/'))
@@ -149,12 +183,11 @@ private val Classifier.fqNameSerialized: String
append(relativeFqName) append(relativeFqName)
} }
private val PropertyStub.flags: Flags val PropertyStub.flags: Flags
get() = listOfNotNull( get() = flagsOfNotNull(
Flag.IS_PUBLIC, Flag.IS_PUBLIC,
Flag.Property.IS_DECLARATION, Flag.Property.IS_DECLARATION,
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }, Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_FINAL.takeIf { modality == MemberStubModality.FINAL },
when (kind) { when (kind) {
is PropertyStub.Kind.Val -> null is PropertyStub.Kind.Val -> null
is PropertyStub.Kind.Var -> Flag.Property.IS_VAR is PropertyStub.Kind.Var -> Flag.Property.IS_VAR
@@ -170,9 +203,9 @@ private val PropertyStub.flags: Flags
is PropertyStub.Kind.Val -> null is PropertyStub.Kind.Val -> null
is PropertyStub.Kind.Var -> Flag.Property.HAS_SETTER is PropertyStub.Kind.Var -> Flag.Property.HAS_SETTER
} }
).let { flagsOf(*it.toTypedArray()) } ) or modality.flags
private val PropertyStub.getterFlags: Flags val PropertyStub.getterFlags: Flags
get() = when (kind) { get() = when (kind) {
is PropertyStub.Kind.Val -> kind.getter.flags is PropertyStub.Kind.Val -> kind.getter.flags
is PropertyStub.Kind.Var -> kind.getter.flags is PropertyStub.Kind.Var -> kind.getter.flags
@@ -180,57 +213,97 @@ private val PropertyStub.getterFlags: Flags
} }
private val PropertyAccessor.Getter.flags: Flags private val PropertyAccessor.Getter.flags: Flags
get() = listOfNotNull( get() = flagsOfNotNull(
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }, Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_PUBLIC, Flag.IS_PUBLIC,
Flag.IS_FINAL, Flag.IS_FINAL,
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Getter.ExternalGetter } Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Getter.ExternalGetter }
).let { flagsOf(*it.toTypedArray()) } )
private val PropertyStub.setterFlags: Flags val PropertyStub.setterFlags: Flags
get() = if (kind !is PropertyStub.Kind.Var) flagsOf() get() = if (kind !is PropertyStub.Kind.Var) flagsOf()
else kind.setter.flags else kind.setter.flags
private val PropertyAccessor.Setter.flags: Flags val PropertyAccessor.Setter.flags: Flags
get() = listOfNotNull( get() = flagsOfNotNull(
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }, Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
Flag.IS_PUBLIC, Flag.IS_PUBLIC,
Flag.IS_FINAL, Flag.IS_FINAL,
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Setter.ExternalSetter } Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Setter.ExternalSetter }
).let { flagsOf(*it.toTypedArray()) } )
private val StubType.flags: Flags val StubType.flags: Flags
get() = listOfNotNull( get() = flagsOfNotNull(
Flag.Type.IS_NULLABLE.takeIf { nullable } Flag.Type.IS_NULLABLE.takeIf { nullable }
).let { flagsOf(*it.toTypedArray()) } )
private val TypealiasStub.flags: Flags val TypealiasStub.flags: Flags
get() = listOfNotNull( get() = flagsOfNotNull(
Flag.IS_PUBLIC Flag.IS_PUBLIC
).let { flagsOf(*it.toTypedArray()) } )
private val FunctionParameterStub.flags: Flags val FunctionParameterStub.flags: Flags
get() = listOfNotNull( get() = flagsOfNotNull(
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() } Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }
).let { flagsOf(*it.toTypedArray()) } )
fun AnnotationStub.map(): KmAnnotation {
fun Pair<String, String>.asAnnotationArgument() =
(first to KmAnnotationArgument.StringValue(second)).takeIf { second.isNotEmpty() }
fun replaceWith(replaceWith: String) = KmAnnotationArgument.AnnotationValue(KmAnnotation(
Classifier.topLevel("kotlin", "ReplaceWith").fqNameSerialized,
mapOfNotNull(
"imports" to KmAnnotationArgument.ArrayValue(emptyList()),
("expression" to replaceWith).asAnnotationArgument()
)
))
fun deprecationLevel(level: DeprecationLevel) = KmAnnotationArgument.EnumValue(
Classifier.topLevel("kotlin", "DeprecationLevel").fqNameSerialized,
level.name
)
private fun AnnotationStub.map(): KmAnnotation {
val args = when (this) { val args = when (this) {
AnnotationStub.ObjC.ConsumesReceiver -> TODO() AnnotationStub.ObjC.ConsumesReceiver -> emptyMap()
AnnotationStub.ObjC.ReturnsRetained -> TODO() AnnotationStub.ObjC.ReturnsRetained -> emptyMap()
is AnnotationStub.ObjC.Method -> TODO() is AnnotationStub.ObjC.Method -> mapOfNotNull(
is AnnotationStub.ObjC.Factory -> TODO() ("selector" to selector).asAnnotationArgument(),
AnnotationStub.ObjC.Consumed -> TODO() ("encoding" to encoding).asAnnotationArgument(),
is AnnotationStub.ObjC.Constructor -> TODO() ("isStret" to KmAnnotationArgument.BooleanValue(isStret))
is AnnotationStub.ObjC.ExternalClass -> TODO() )
AnnotationStub.CCall.CString -> mapOf() is AnnotationStub.ObjC.Factory -> mapOfNotNull(
AnnotationStub.CCall.WCString -> mapOf() ("selector" to selector).asAnnotationArgument(),
is AnnotationStub.CCall.Symbol -> ("encoding" to encoding).asAnnotationArgument(),
mapOf("id" to KmAnnotationArgument.StringValue(symbolName)) ("isStret" to KmAnnotationArgument.BooleanValue(isStret))
is AnnotationStub.CStruct -> TODO() )
is AnnotationStub.CNaturalStruct -> TODO() AnnotationStub.ObjC.Consumed -> emptyMap()
is AnnotationStub.CLength -> TODO() is AnnotationStub.ObjC.Constructor -> mapOfNotNull(
is AnnotationStub.Deprecated -> TODO() ("designated" to KmAnnotationArgument.BooleanValue(designated)),
("initSelector" to selector).asAnnotationArgument()
)
is AnnotationStub.ObjC.ExternalClass -> mapOfNotNull(
("protocolGetter" to protocolGetter).asAnnotationArgument(),
("binaryName" to binaryName).asAnnotationArgument()
)
AnnotationStub.CCall.CString -> emptyMap()
AnnotationStub.CCall.WCString -> emptyMap()
is AnnotationStub.CCall.Symbol -> mapOfNotNull(
("id" to symbolName).asAnnotationArgument()
)
is AnnotationStub.CStruct -> mapOfNotNull(
("spelling" to struct).asAnnotationArgument()
)
is AnnotationStub.CNaturalStruct ->
error("@CNaturalStruct should not be used for Kotlin/Native interop")
is AnnotationStub.CLength -> mapOfNotNull(
"value" to KmAnnotationArgument.LongValue(length)
)
is AnnotationStub.Deprecated -> mapOfNotNull(
("message" to message).asAnnotationArgument(),
("replaceWith" to replaceWith(replaceWith)),
("level" to deprecationLevel(DeprecationLevel.ERROR))
)
} }
return KmAnnotation(classifier.fqNameSerialized, args) return KmAnnotation(classifier.fqNameSerialized, args)
} }
@@ -255,7 +328,7 @@ private fun AnnotationStub.map(): KmAnnotation {
* As of 25 Nov 2019, the latter form is used only for KmTypeAlias.underlyingType. * As of 25 Nov 2019, the latter form is used only for KmTypeAlias.underlyingType.
*/ */
// TODO: Add caching if needed. // TODO: Add caching if needed.
private fun StubType.map(shouldExpandTypeAliases: Boolean = true): KmType = when (this) { fun StubType.map(shouldExpandTypeAliases: Boolean = true): KmType = when (this) {
is AbbreviatedType -> { is AbbreviatedType -> {
val typeAliasClassifier = KmClassifier.TypeAlias(abbreviatedClassifier.fqNameSerialized) val typeAliasClassifier = KmClassifier.TypeAlias(abbreviatedClassifier.fqNameSerialized)
if (shouldExpandTypeAliases) { if (shouldExpandTypeAliases) {
@@ -283,7 +356,7 @@ private fun StubType.map(shouldExpandTypeAliases: Boolean = true): KmType = when
} }
} }
private fun FunctionParameterStub.map(): KmValueParameter = fun FunctionParameterStub.map(): KmValueParameter =
KmValueParameter(flags, name).also { km -> KmValueParameter(flags, name).also { km ->
val kmType = type.map() val kmType = type.map()
if (isVararg) { if (isVararg) {
@@ -291,10 +364,10 @@ private fun FunctionParameterStub.map(): KmValueParameter =
} else { } else {
km.type = kmType km.type = kmType
} }
annotations.mapTo(km.annotations, AnnotationStub::map) annotations.mapTo(km.annotations, { it.map() })
} }
private fun TypeParameterStub.map(): KmTypeParameter = fun TypeParameterStub.map(): KmTypeParameter =
KmTypeParameter(flagsOf(), name, id, KmVariance.INVARIANT).also { km -> KmTypeParameter(flagsOf(), name, id, KmVariance.INVARIANT).also { km ->
km.upperBounds.addIfNotNull(upperBound?.map()) km.upperBounds.addIfNotNull(upperBound?.map())
} }
@@ -311,7 +384,7 @@ private fun TypeArgument.Variance.map(): KmVariance = when (this) {
TypeArgument.Variance.OUT -> KmVariance.OUT TypeArgument.Variance.OUT -> KmVariance.OUT
} }
private fun ConstantStub.mapToAnnotationArgument(): KmAnnotationArgument<*> = when (this) { fun ConstantStub.mapToAnnotationArgument(): KmAnnotationArgument<*> = when (this) {
is StringConstantStub -> KmAnnotationArgument.StringValue(value) is StringConstantStub -> KmAnnotationArgument.StringValue(value)
is IntegralConstantStub -> when (size) { is IntegralConstantStub -> when (size) {
1 -> if (isSigned) { 1 -> if (isSigned) {
@@ -345,7 +418,8 @@ private fun ConstantStub.mapToAnnotationArgument(): KmAnnotationArgument<*> = wh
} }
private val TypeParameterType.id: Int private val TypeParameterType.id: Int
get() = TODO() get() = typeParameterDeclaration.id
private val TypeParameterStub.id: Int private val TypeParameterStub.id: Int
get() = TODO() get() = typeParametersInterner.intern(this)
}
@@ -65,7 +65,8 @@ class FunctionalType(
class TypeParameterType( class TypeParameterType(
val name: String, val name: String,
override val nullable: Boolean override val nullable: Boolean,
val typeParameterDeclaration: TypeParameterStub
) : StubType() { ) : StubType() {
override val typeArguments: List<TypeArgument> = emptyList() override val typeArguments: List<TypeArgument> = emptyList()
} }