[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:
committed by
Sergey Bogolepov
parent
7e0a65e480
commit
37f9161ec2
+1
-1
@@ -59,7 +59,7 @@ class TypeParameterStub(
|
||||
val upperBound: StubType? = null
|
||||
) {
|
||||
fun getStubType(nullable: Boolean) =
|
||||
TypeParameterType(name, nullable = nullable)
|
||||
TypeParameterType(name, nullable = nullable, typeParameterDeclaration = this)
|
||||
|
||||
}
|
||||
|
||||
|
||||
+312
-238
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.native.interop.gen
|
||||
|
||||
import kotlinx.metadata.*
|
||||
import kotlinx.metadata.klib.*
|
||||
import org.jetbrains.kotlin.metadata.serialization.Interner
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class StubIrMetadataEmitter(
|
||||
@@ -69,7 +70,8 @@ internal class ModuleMetadataEmitter(
|
||||
*/
|
||||
private data class VisitingContext(
|
||||
val container: StubContainer? = null,
|
||||
val uniqIds: StubIrUniqIdProvider
|
||||
val uniqIds: StubIrUniqIdProvider,
|
||||
val typeParametersInterner: Interner<TypeParameterStub> = Interner()
|
||||
)
|
||||
|
||||
private val visitor = object : StubIrVisitor<VisitingContext, Any> {
|
||||
@@ -79,41 +81,47 @@ internal class ModuleMetadataEmitter(
|
||||
}
|
||||
|
||||
override fun visitTypealias(element: TypealiasStub, data: VisitingContext): KmTypeAlias =
|
||||
KmTypeAlias(element.flags, element.alias.topLevelName).also { km ->
|
||||
km.uniqId = data.uniqIds.uniqIdForTypeAlias(element)
|
||||
km.underlyingType = element.aliasee.map(shouldExpandTypeAliases = false)
|
||||
km.expandedType = element.aliasee.map()
|
||||
}
|
||||
with (MappingExtensions(data.typeParametersInterner)) {
|
||||
KmTypeAlias(element.flags, element.alias.topLevelName).also { km ->
|
||||
km.uniqId = data.uniqIds.uniqIdForTypeAlias(element)
|
||||
km.underlyingType = element.aliasee.map(shouldExpandTypeAliases = false)
|
||||
km.expandedType = element.aliasee.map()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(element: FunctionStub, data: VisitingContext) =
|
||||
KmFunction(element.flags, element.name).also { km ->
|
||||
element.annotations.mapTo(km.annotations, AnnotationStub::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)
|
||||
}
|
||||
with (MappingExtensions(data.typeParametersInterner)) {
|
||||
KmFunction(element.flags, element.name).also { km ->
|
||||
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.uniqId = data.uniqIds.uniqIdForFunction(element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitProperty(element: PropertyStub, data: VisitingContext) =
|
||||
KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).also { km ->
|
||||
element.annotations.mapTo(km.annotations, AnnotationStub::map)
|
||||
km.uniqId = data.uniqIds.uniqIdForProperty(element)
|
||||
km.returnType = element.type.map()
|
||||
if (element.kind is PropertyStub.Kind.Var) {
|
||||
val setter = element.kind.setter
|
||||
setter.annotations.mapTo(km.setterAnnotations, AnnotationStub::map)
|
||||
// TODO: Maybe it's better to explicitly add setter parameter in stub.
|
||||
km.setterParameter = FunctionParameterStub("value", element.type).map()
|
||||
with (MappingExtensions(data.typeParametersInterner)) {
|
||||
KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).also { km ->
|
||||
element.annotations.mapTo(km.annotations) { it.map() }
|
||||
km.uniqId = data.uniqIds.uniqIdForProperty(element)
|
||||
km.returnType = element.type.map()
|
||||
if (element.kind is PropertyStub.Kind.Var) {
|
||||
val setter = element.kind.setter
|
||||
setter.annotations.mapTo(km.setterAnnotations) { it.map() }
|
||||
// TODO: Maybe it's better to explicitly add setter parameter in stub.
|
||||
km.setterParameter = FunctionParameterStub("value", element.type).map()
|
||||
}
|
||||
km.getterAnnotations += when (element.kind) {
|
||||
is PropertyStub.Kind.Val -> element.kind.getter.annotations.map { it.map() }
|
||||
is PropertyStub.Kind.Var -> element.kind.getter.annotations.map { it.map() }
|
||||
is PropertyStub.Kind.Constant -> emptyList()
|
||||
}
|
||||
if (element.kind is PropertyStub.Kind.Constant) {
|
||||
km.compileTimeValue = element.kind.constant.mapToAnnotationArgument()
|
||||
}
|
||||
}
|
||||
}
|
||||
km.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) {
|
||||
km.compileTimeValue = element.kind.constant.mapToAnnotationArgument()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructor(constructorStub: ConstructorStub, data: VisitingContext) {
|
||||
// TODO("not implemented")
|
||||
@@ -129,223 +137,289 @@ internal class ModuleMetadataEmitter(
|
||||
}
|
||||
}
|
||||
|
||||
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 },
|
||||
Flag.IS_ABSTRACT.takeIf { modality == MemberStubModality.ABSTRACT }
|
||||
).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.
|
||||
* Collection of extension functions that simplify translation of
|
||||
* StubIr elements to Kotlin Metadata.
|
||||
*/
|
||||
// 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 class MappingExtensions(
|
||||
private val typeParametersInterner: Interner<TypeParameterStub>
|
||||
) {
|
||||
|
||||
private fun FunctionParameterStub.map(): KmValueParameter =
|
||||
KmValueParameter(flags, name).also { km ->
|
||||
val kmType = type.map()
|
||||
if (isVararg) {
|
||||
km.varargElementType = kmType
|
||||
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 {
|
||||
if (pkg.isNotEmpty()) {
|
||||
append(pkg.replace('.', '/'))
|
||||
append('/')
|
||||
}
|
||||
// Nested classes should dot-separated.
|
||||
append(relativeFqName)
|
||||
}
|
||||
|
||||
val PropertyStub.flags: Flags
|
||||
get() = flagsOfNotNull(
|
||||
Flag.IS_PUBLIC,
|
||||
Flag.Property.IS_DECLARATION,
|
||||
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
|
||||
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
|
||||
}
|
||||
) or modality.flags
|
||||
|
||||
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() = flagsOfNotNull(
|
||||
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
|
||||
Flag.IS_PUBLIC,
|
||||
Flag.IS_FINAL,
|
||||
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Getter.ExternalGetter }
|
||||
)
|
||||
|
||||
val PropertyStub.setterFlags: Flags
|
||||
get() = if (kind !is PropertyStub.Kind.Var) flagsOf()
|
||||
else kind.setter.flags
|
||||
|
||||
val PropertyAccessor.Setter.flags: Flags
|
||||
get() = flagsOfNotNull(
|
||||
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() },
|
||||
Flag.IS_PUBLIC,
|
||||
Flag.IS_FINAL,
|
||||
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { this is PropertyAccessor.Setter.ExternalSetter }
|
||||
)
|
||||
|
||||
val StubType.flags: Flags
|
||||
get() = flagsOfNotNull(
|
||||
Flag.Type.IS_NULLABLE.takeIf { nullable }
|
||||
)
|
||||
|
||||
val TypealiasStub.flags: Flags
|
||||
get() = flagsOfNotNull(
|
||||
Flag.IS_PUBLIC
|
||||
)
|
||||
|
||||
val FunctionParameterStub.flags: Flags
|
||||
get() = flagsOfNotNull(
|
||||
Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
val args = when (this) {
|
||||
AnnotationStub.ObjC.ConsumesReceiver -> emptyMap()
|
||||
AnnotationStub.ObjC.ReturnsRetained -> emptyMap()
|
||||
is AnnotationStub.ObjC.Method -> mapOfNotNull(
|
||||
("selector" to selector).asAnnotationArgument(),
|
||||
("encoding" to encoding).asAnnotationArgument(),
|
||||
("isStret" to KmAnnotationArgument.BooleanValue(isStret))
|
||||
)
|
||||
is AnnotationStub.ObjC.Factory -> mapOfNotNull(
|
||||
("selector" to selector).asAnnotationArgument(),
|
||||
("encoding" to encoding).asAnnotationArgument(),
|
||||
("isStret" to KmAnnotationArgument.BooleanValue(isStret))
|
||||
)
|
||||
AnnotationStub.ObjC.Consumed -> emptyMap()
|
||||
is AnnotationStub.ObjC.Constructor -> mapOfNotNull(
|
||||
("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)
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
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 {
|
||||
km.type = kmType
|
||||
KmType(flags).also { km -> km.classifier = typeAliasClassifier }
|
||||
}
|
||||
annotations.mapTo(km.annotations, AnnotationStub::map)
|
||||
}
|
||||
|
||||
private fun TypeParameterStub.map(): KmTypeParameter =
|
||||
KmTypeParameter(flagsOf(), name, id, KmVariance.INVARIANT).also { km ->
|
||||
km.upperBounds.addIfNotNull(upperBound?.map())
|
||||
is ClassifierStubType -> KmType(flags).also { km ->
|
||||
typeArguments.mapTo(km.arguments) { it.map(shouldExpandTypeAliases) }
|
||||
km.classifier = KmClassifier.Class(classifier.fqNameSerialized)
|
||||
}
|
||||
|
||||
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.mapToAnnotationArgument(): KmAnnotationArgument<*> = when (this) {
|
||||
is StringConstantStub -> KmAnnotationArgument.StringValue(value)
|
||||
is IntegralConstantStub -> when (size) {
|
||||
1 -> if (isSigned) {
|
||||
KmAnnotationArgument.ByteValue(value.toByte())
|
||||
} else {
|
||||
KmAnnotationArgument.UByteValue(value.toByte())
|
||||
is FunctionalType -> KmType(flags).also { km ->
|
||||
typeArguments.mapTo(km.arguments) { it.map(shouldExpandTypeAliases) }
|
||||
km.classifier = KmClassifier.Class(classifier.fqNameSerialized)
|
||||
}
|
||||
2 -> if (isSigned) {
|
||||
KmAnnotationArgument.ShortValue(value.toShort())
|
||||
} else {
|
||||
KmAnnotationArgument.UShortValue(value.toShort())
|
||||
is TypeParameterType -> KmType(flags).also { km ->
|
||||
km.classifier = KmClassifier.TypeParameter(id)
|
||||
}
|
||||
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.")
|
||||
|
||||
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, { it.map() })
|
||||
}
|
||||
|
||||
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 val TypeParameterType.id: Int
|
||||
get() = TODO()
|
||||
private fun TypeArgument.Variance.map(): KmVariance = when (this) {
|
||||
TypeArgument.Variance.INVARIANT -> KmVariance.INVARIANT
|
||||
TypeArgument.Variance.IN -> KmVariance.IN
|
||||
TypeArgument.Variance.OUT -> KmVariance.OUT
|
||||
}
|
||||
|
||||
private val TypeParameterStub.id: Int
|
||||
get() = TODO()
|
||||
fun ConstantStub.mapToAnnotationArgument(): 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() = typeParameterDeclaration.id
|
||||
|
||||
private val TypeParameterStub.id: Int
|
||||
get() = typeParametersInterner.intern(this)
|
||||
}
|
||||
+2
-1
@@ -65,7 +65,8 @@ class FunctionalType(
|
||||
|
||||
class TypeParameterType(
|
||||
val name: String,
|
||||
override val nullable: Boolean
|
||||
override val nullable: Boolean,
|
||||
val typeParameterDeclaration: TypeParameterStub
|
||||
) : StubType() {
|
||||
override val typeArguments: List<TypeArgument> = emptyList()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user