kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal.impl.serialization.deserialization
import kotlin.reflect.jvm.internal.impl.descriptors.CallableDescriptor
import kotlin.reflect.jvm.internal.impl.descriptors.ClassDescriptor
import kotlin.reflect.jvm.internal.impl.descriptors.TypeParameterDescriptor
import kotlin.reflect.jvm.internal.impl.descriptors.annotations.Annotations
import kotlin.reflect.jvm.internal.impl.serialization.ProtoBuf
import kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedTypeParameterDescriptor
import kotlin.reflect.jvm.internal.impl.types.*
import kotlin.reflect.jvm.internal.impl.utils.toReadOnlyList
import java.util.*
class TypeDeserializer(
private val c: DeserializationContext,
private val parent: TypeDeserializer?,
private val typeParameterProtos: List,
private val debugName: String
) {
private val classDescriptors: (Int) -> ClassDescriptor? = c.storageManager.createMemoizedFunctionWithNullableValues {
fqNameIndex -> computeClassDescriptor(fqNameIndex)
}
private val typeParameterDescriptors = c.storageManager.createLazyValue {
if (typeParameterProtos.isEmpty()) {
mapOf()
}
else {
val result = LinkedHashMap()
for ((index, proto) in typeParameterProtos.withIndex()) {
result[proto.id] = DeserializedTypeParameterDescriptor(c, proto, index)
}
result
}
}
val ownTypeParameters: List
get() = typeParameterDescriptors().values.toReadOnlyList()
// TODO: don't load identical types from TypeTable more than once
fun type(proto: ProtoBuf.Type, additionalAnnotations: Annotations = Annotations.EMPTY): KotlinType {
if (proto.hasFlexibleTypeCapabilitiesId()) {
val id = c.nameResolver.getString(proto.flexibleTypeCapabilitiesId)
val capabilities = c.components.flexibleTypeCapabilitiesDeserializer.capabilitiesById(id) ?:
return ErrorUtils.createErrorType("${DeserializedType(c, proto)}: Capabilities not found for id $id")
return DelegatingFlexibleType.create(
DeserializedType(c, proto),
DeserializedType(c, proto.flexibleUpperBound(c.typeTable)!!),
capabilities
)
}
return DeserializedType(c, proto, additionalAnnotations)
}
fun typeConstructor(proto: ProtoBuf.Type): TypeConstructor =
when {
proto.hasClassName() ->
classDescriptors(proto.className)?.typeConstructor
proto.hasTypeParameter() ->
typeParameterTypeConstructor(proto.typeParameter)
proto.hasTypeParameterName() -> {
val container = c.containingDeclaration
val typeParameters = when (container) {
is ClassDescriptor -> container.typeConstructor.parameters
is CallableDescriptor -> container.typeParameters
else -> emptyList()
}
val name = c.nameResolver.getString(proto.typeParameterName)
val parameter = typeParameters.find { it.name.asString() == name }
parameter?.typeConstructor ?: ErrorUtils.createErrorType("Deserialized type parameter $name in $container").constructor
}
else ->
null
} ?: ErrorUtils.createErrorType(presentableTextForErrorType(proto)).constructor
internal fun presentableTextForErrorType(proto: ProtoBuf.Type): String = when {
proto.hasClassName() ->
c.nameResolver.getClassId(proto.className).asSingleFqName().asString()
proto.hasTypeParameter() ->
"Unknown type parameter ${proto.typeParameter}"
proto.hasTypeParameterName() ->
"Unknown type parameter ${c.nameResolver.getString(proto.typeParameterName)}"
else ->
"Unknown type"
}
private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? =
typeParameterDescriptors().get(typeParameterId)?.typeConstructor ?:
parent?.typeParameterTypeConstructor(typeParameterId)
private fun computeClassDescriptor(fqNameIndex: Int): ClassDescriptor? {
val id = c.nameResolver.getClassId(fqNameIndex)
if (id.isLocal) {
// Local classes can't be found in scopes
return c.components.localClassResolver.resolveLocalClass(id)
}
return c.components.moduleDescriptor.findClassAcrossModuleDependencies(id)
}
fun typeArgument(parameter: TypeParameterDescriptor?, typeArgumentProto: ProtoBuf.Type.Argument): TypeProjection {
if (typeArgumentProto.projection == ProtoBuf.Type.Argument.Projection.STAR) {
return if (parameter == null)
TypeBasedStarProjectionImpl(c.components.moduleDescriptor.builtIns.nullableAnyType)
else
StarProjectionImpl(parameter)
}
val variance = Deserialization.variance(typeArgumentProto.projection)
val type = typeArgumentProto.type(c.typeTable) ?:
return TypeProjectionImpl(ErrorUtils.createErrorType("No type recorded"))
return TypeProjectionImpl(variance, type(type))
}
override fun toString() = debugName + (if (parent == null) "" else ". Child of ${parent.debugName}")
}