Add information about secondary constructors to synthetic classes.

Before this, descriptors for such constructors were created in-place where they needed by the codegens.
However, presence of symbol table in IR backend requires the single instance of constructor descriptor across all compilation to be able to reference it and create a symbol. This support of generics in kotlinx.serialization on Kotlin/Native.
This commit is contained in:
Leonid Startsev
2018-10-01 15:25:02 +03:00
parent 01d3c7bdc8
commit a4a1df0a81
7 changed files with 66 additions and 57 deletions
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -441,7 +442,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
try {
lookupConstructorExpressionsInClosureIfPresent();
constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, superClassAsmType);
if (!descriptor.isInline()) {
if (!descriptor.isInline() && !(descriptor instanceof SyntheticClassOrObjectDescriptor)) {
// Synthetic classes does not have declarations for secondary constructors
for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
constructorCodegen.generateSecondaryConstructor(secondaryConstructor, superClassAsmType);
}
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.AbstractClassTypeConstructor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import java.lang.IllegalStateException
/*
* This class introduces all attributes that are needed for synthetic classes/object so far.
@@ -52,6 +51,8 @@ class SyntheticClassOrObjectDescriptor(
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
private lateinit var typeParameters: List<TypeParameterDescriptor>
public var secondaryConstructors: List<ClassConstructorDescriptor> = emptyList()
private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, c.languageVersionSettings, { outerScope })
private val syntheticSupertypes =
@@ -62,7 +63,9 @@ class SyntheticClassOrObjectDescriptor(
c.storageManager.createLazyValue { createUnsubstitutedPrimaryConstructor(constructorVisibility) }
@JvmOverloads
fun initialize(typeParameters: List<TypeParameterDescriptor> = emptyList()) {
fun initialize(
typeParameters: List<TypeParameterDescriptor> = emptyList()
) {
this.typeParameters = typeParameters
}
@@ -81,7 +84,7 @@ class SyntheticClassOrObjectDescriptor(
override fun getCompanionObjectDescriptor(): ClassDescriptorWithResolutionScopes? = null
override fun getTypeConstructor(): TypeConstructor = typeConstructor
override fun getUnsubstitutedPrimaryConstructor() = _unsubstitutedPrimaryConstructor()
override fun getConstructors() = listOf(_unsubstitutedPrimaryConstructor())
override fun getConstructors() = listOf(_unsubstitutedPrimaryConstructor()) + secondaryConstructors
override fun getDeclaredTypeParameters() = typeParameters
override fun getStaticScope() = MemberScope.Empty
override fun getUnsubstitutedMemberScope() = unsubstitutedMemberScope
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers
abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor,
@@ -45,8 +45,10 @@ abstract class SerializerCodegen(
generateDescriptorGetterIfNeeded()
// if (save || load || prop)
// generateSerialDesc()
if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) {
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
findSerializerConstructorForTypeArgumentsSerializers(serializerDescriptor)?.let {
generateGenericFieldsAndConstructor(it)
}
}
}
@@ -63,24 +65,6 @@ abstract class SerializerCodegen(
// TODO()
}
// checks if user didn't declared constructor (KSerializer<T0>, KSerializer<T1>...) on a KSerializer<T<T0, T1...>>
private fun typedSerializerConstructorNotDeclared(): Boolean {
val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializerDescriptor)?.arguments
?: throw AssertionError("Serializer does not implement KSerializer??")
val typeParamsCount = serializableImplementationTypeArguments.size
if (typeParamsCount == 0) return false //don't need it
val ctors = serializerDescriptor.constructors
val found =
ctors.any {
it.valueParameters.size == typeParamsCount && it.valueParameters.foldIndexed(false) { index, flag, parameterDescriptor ->
val type = parameterDescriptor.type
flag || (isKSerializer(type) && type.arguments.first() == serializableImplementationTypeArguments[index])
}
}
return !found
}
protected val generatedSerialDescPropertyDescriptor = getPropertyToGenerate(
serializerDescriptor, SerialEntityNames.SERIAL_DESC_FIELD,
serializerDescriptor::checkSerializableClassPropertyResult)
@@ -6,7 +6,6 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -25,8 +24,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsNew
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
@@ -34,9 +31,6 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator
import org.jetbrains.kotlinx.serialization.compiler.backend.js.serializerInstance
import org.jetbrains.kotlinx.serialization.compiler.backend.js.translateQualifiedReference
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
@@ -375,15 +369,15 @@ interface IrBuilderExtension {
}
fun IrBuilderWithScope.serializerInstance(
enclosingGenerator: AbstractSerialGenerator,
serializableDescriptor: ClassDescriptor,
serializerClass: ClassDescriptor?,
module: ModuleDescriptor,
kType: KotlinType,
genericIndex: Int? = null
enclosingGenerator: AbstractSerialGenerator,
serializableDescriptor: ClassDescriptor,
serializerClass: ClassDescriptor?,
module: ModuleDescriptor,
kType: KotlinType,
genericIndex: Int? = null
): IrExpression? {
val nullableSerClass =
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
if (serializerClass == null) {
if (genericIndex == null) return null
TODO("Saved serializer for generic argument")
@@ -395,22 +389,25 @@ interface IrBuilderExtension {
TODO("enum and context serializer")
else kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex) ?: return null
val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex)
?: return null
// todo: smth better than constructors[0] ??
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr
}
if (serializerClass.classId == referenceArraySerializerId) TODO("reference array serializer")
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
.let { compilerContext.externalSymbols.referenceConstructor(it) }
requireNotNull(
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
.let { compilerContext.externalSymbols.referenceConstructor(it) }
} else {
compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
}
return irInvoke(
null,
ctor,
*args.toTypedArray()
null,
ctor,
*args.toTypedArray()
)
}
}
@@ -156,7 +156,9 @@ internal fun SerializerJsTranslator.serializerInstance(
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
val desc = requireNotNull(
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
JsInvocation(context.getInnerReference(desc), args)
} else {
JsNew(context.translateQualifiedReference(serializerClass), args)
@@ -43,7 +43,9 @@ class SerializableCompanionJsTranslator(
} else {
val args = jsFun.parameters.map { JsNameRef(it.name) }
val ref = context.getInnerNameForDescriptor(
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializer, serializableDescriptor))
requireNotNull(
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializer)
) { "Generated serializer does not have constructor with required number of arguments" })
JsInvocation(ref.makeRef(), args)
}
+JsReturn(stmt)
@@ -97,7 +97,8 @@ object KSerializerDescriptorResolver {
): ClassDescriptor {
val thisDeclaration = declarationProvider.correspondingClassOrObject!!
val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor)
val serializerKind = if (thisDescriptor.declaredTypeParameters.isNotEmpty()) ClassKind.CLASS else ClassKind.OBJECT
val hasTypeParams = thisDescriptor.declaredTypeParameters.isNotEmpty()
val serializerKind = if (hasTypeParams) ClassKind.CLASS else ClassKind.OBJECT
val serializerDescriptor = SyntheticClassOrObjectDescriptor(
ctx,
thisDeclaration,
@@ -114,6 +115,12 @@ object KSerializerDescriptorResolver {
)
}
serializerDescriptor.initialize(typeParameters)
val secondaryCtors =
if (!hasTypeParams)
emptyList()
else
listOf(createTypedSerializerConstructorDescriptor(serializerDescriptor, thisDescriptor, typeParameters))
serializerDescriptor.secondaryConstructors = secondaryCtors
return serializerDescriptor
}
@@ -286,9 +293,22 @@ object KSerializerDescriptorResolver {
return functionDescriptor
}
fun createTypedSerializerConstructorDescriptor(
// finds constructor (KSerializer<T0>, KSerializer<T1>...) on a KSerializer<T<T0, T1...>>
fun findSerializerConstructorForTypeArgumentsSerializers(serializerDescriptor: ClassDescriptor): ClassConstructorDescriptor? {
val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializerDescriptor)?.arguments
?: throw AssertionError("Serializer does not implement KSerializer??")
val typeParamsCount = serializableImplementationTypeArguments.size
if (typeParamsCount == 0) return null //don't need it
return serializerDescriptor.constructors.find { ctor ->
ctor.valueParameters.size == typeParamsCount && ctor.valueParameters.all { isKSerializer(it.type) }
}
}
private fun createTypedSerializerConstructorDescriptor(
classDescriptor: ClassDescriptor,
serializableDescriptor: ClassDescriptor
serializableDescriptor: ClassDescriptor,
typeParameters: List<TypeParameterDescriptor>
): ClassConstructorDescriptor {
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor,
@@ -297,24 +317,23 @@ object KSerializerDescriptorResolver {
classDescriptor.source
)
val serializerClass = classDescriptor.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS)
val targs = mutableListOf<TypeParameterDescriptor>()
assert(serializableDescriptor.declaredTypeParameters.size == typeParameters.size)
val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, param ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(
constrDesc, Annotations.EMPTY, false, Variance.INVARIANT,
param.name, index
)
val pType =
KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType)))
KotlinTypeFactory.simpleNotNullType(
Annotations.EMPTY,
serializerClass,
listOf(TypeProjectionImpl(typeParameters[index].defaultType))
)
targs.add(targ)
ValueParameterDescriptorImpl(
constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType,
false, false, false, null, constrDesc.source
)
}
constrDesc.initialize(args, Visibilities.PUBLIC, targs)
constrDesc.initialize(args, Visibilities.PUBLIC, typeParameters)
constrDesc.returnType = classDescriptor.defaultType
return constrDesc
}