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.FqName;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -441,7 +442,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
try { try {
lookupConstructorExpressionsInClosureIfPresent(); lookupConstructorExpressionsInClosureIfPresent();
constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, superClassAsmType); 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)) { for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
constructorCodegen.generateSecondaryConstructor(secondaryConstructor, superClassAsmType); 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.AbstractClassTypeConstructor
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import java.lang.IllegalStateException
/* /*
* This class introduces all attributes that are needed for synthetic classes/object so far. * 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 val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
private lateinit var typeParameters: List<TypeParameterDescriptor> private lateinit var typeParameters: List<TypeParameterDescriptor>
public var secondaryConstructors: List<ClassConstructorDescriptor> = emptyList()
private val typeConstructor = SyntheticTypeConstructor(c.storageManager) private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, c.languageVersionSettings, { outerScope }) private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, c.languageVersionSettings, { outerScope })
private val syntheticSupertypes = private val syntheticSupertypes =
@@ -62,7 +63,9 @@ class SyntheticClassOrObjectDescriptor(
c.storageManager.createLazyValue { createUnsubstitutedPrimaryConstructor(constructorVisibility) } c.storageManager.createLazyValue { createUnsubstitutedPrimaryConstructor(constructorVisibility) }
@JvmOverloads @JvmOverloads
fun initialize(typeParameters: List<TypeParameterDescriptor> = emptyList()) { fun initialize(
typeParameters: List<TypeParameterDescriptor> = emptyList()
) {
this.typeParameters = typeParameters this.typeParameters = typeParameters
} }
@@ -81,7 +84,7 @@ class SyntheticClassOrObjectDescriptor(
override fun getCompanionObjectDescriptor(): ClassDescriptorWithResolutionScopes? = null override fun getCompanionObjectDescriptor(): ClassDescriptorWithResolutionScopes? = null
override fun getTypeConstructor(): TypeConstructor = typeConstructor override fun getTypeConstructor(): TypeConstructor = typeConstructor
override fun getUnsubstitutedPrimaryConstructor() = _unsubstitutedPrimaryConstructor() override fun getUnsubstitutedPrimaryConstructor() = _unsubstitutedPrimaryConstructor()
override fun getConstructors() = listOf(_unsubstitutedPrimaryConstructor()) override fun getConstructors() = listOf(_unsubstitutedPrimaryConstructor()) + secondaryConstructors
override fun getDeclaredTypeParameters() = typeParameters override fun getDeclaredTypeParameters() = typeParameters
override fun getStaticScope() = MemberScope.Empty override fun getStaticScope() = MemberScope.Empty
override fun getUnsubstitutedMemberScope() = unsubstitutedMemberScope 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.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlinx.serialization.compiler.resolve.* 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( abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor, protected val serializerDescriptor: ClassDescriptor,
@@ -45,8 +45,10 @@ abstract class SerializerCodegen(
generateDescriptorGetterIfNeeded() generateDescriptorGetterIfNeeded()
// if (save || load || prop) // if (save || load || prop)
// generateSerialDesc() // generateSerialDesc()
if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) { if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor)) findSerializerConstructorForTypeArgumentsSerializers(serializerDescriptor)?.let {
generateGenericFieldsAndConstructor(it)
}
} }
} }
@@ -63,24 +65,6 @@ abstract class SerializerCodegen(
// TODO() // 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( protected val generatedSerialDescPropertyDescriptor = getPropertyToGenerate(
serializerDescriptor, SerialEntityNames.SERIAL_DESC_FIELD, serializerDescriptor, SerialEntityNames.SERIAL_DESC_FIELD,
serializerDescriptor::checkSerializableClassPropertyResult) serializerDescriptor::checkSerializableClassPropertyResult)
@@ -6,7 +6,6 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext 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.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.* 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.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId 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.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator 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.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.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
@@ -375,15 +369,15 @@ interface IrBuilderExtension {
} }
fun IrBuilderWithScope.serializerInstance( fun IrBuilderWithScope.serializerInstance(
enclosingGenerator: AbstractSerialGenerator, enclosingGenerator: AbstractSerialGenerator,
serializableDescriptor: ClassDescriptor, serializableDescriptor: ClassDescriptor,
serializerClass: ClassDescriptor?, serializerClass: ClassDescriptor?,
module: ModuleDescriptor, module: ModuleDescriptor,
kType: KotlinType, kType: KotlinType,
genericIndex: Int? = null genericIndex: Int? = null
): IrExpression? { ): IrExpression? {
val nullableSerClass = val nullableSerClass =
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
if (serializerClass == null) { if (serializerClass == null) {
if (genericIndex == null) return null if (genericIndex == null) return null
TODO("Saved serializer for generic argument") TODO("Saved serializer for generic argument")
@@ -395,22 +389,25 @@ interface IrBuilderExtension {
TODO("enum and context serializer") TODO("enum and context serializer")
else kType.arguments.map { else kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi()) 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] ?? // todo: smth better than constructors[0] ??
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr
} }
if (serializerClass.classId == referenceArraySerializerId) TODO("reference array serializer") if (serializerClass.classId == referenceArraySerializerId) TODO("reference array serializer")
val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor) requireNotNull(
.let { compilerContext.externalSymbols.referenceConstructor(it) } KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
.let { compilerContext.externalSymbols.referenceConstructor(it) }
} else { } else {
compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!) compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
} }
return irInvoke( return irInvoke(
null, null,
ctor, ctor,
*args.toTypedArray() *args.toTypedArray()
) )
} }
} }
@@ -156,7 +156,9 @@ internal fun SerializerJsTranslator.serializerInstance(
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { 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) JsInvocation(context.getInnerReference(desc), args)
} else { } else {
JsNew(context.translateQualifiedReference(serializerClass), args) JsNew(context.translateQualifiedReference(serializerClass), args)
@@ -43,7 +43,9 @@ class SerializableCompanionJsTranslator(
} else { } else {
val args = jsFun.parameters.map { JsNameRef(it.name) } val args = jsFun.parameters.map { JsNameRef(it.name) }
val ref = context.getInnerNameForDescriptor( 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) JsInvocation(ref.makeRef(), args)
} }
+JsReturn(stmt) +JsReturn(stmt)
@@ -97,7 +97,8 @@ object KSerializerDescriptorResolver {
): ClassDescriptor { ): ClassDescriptor {
val thisDeclaration = declarationProvider.correspondingClassOrObject!! val thisDeclaration = declarationProvider.correspondingClassOrObject!!
val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor) 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( val serializerDescriptor = SyntheticClassOrObjectDescriptor(
ctx, ctx,
thisDeclaration, thisDeclaration,
@@ -114,6 +115,12 @@ object KSerializerDescriptorResolver {
) )
} }
serializerDescriptor.initialize(typeParameters) serializerDescriptor.initialize(typeParameters)
val secondaryCtors =
if (!hasTypeParams)
emptyList()
else
listOf(createTypedSerializerConstructorDescriptor(serializerDescriptor, thisDescriptor, typeParameters))
serializerDescriptor.secondaryConstructors = secondaryCtors
return serializerDescriptor return serializerDescriptor
} }
@@ -286,9 +293,22 @@ object KSerializerDescriptorResolver {
return functionDescriptor 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, classDescriptor: ClassDescriptor,
serializableDescriptor: ClassDescriptor serializableDescriptor: ClassDescriptor,
typeParameters: List<TypeParameterDescriptor>
): ClassConstructorDescriptor { ): ClassConstructorDescriptor {
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized( val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor, classDescriptor,
@@ -297,24 +317,23 @@ object KSerializerDescriptorResolver {
classDescriptor.source classDescriptor.source
) )
val serializerClass = classDescriptor.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS) 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 args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, param ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(
constrDesc, Annotations.EMPTY, false, Variance.INVARIANT,
param.name, index
)
val pType = 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( ValueParameterDescriptorImpl(
constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType, constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType,
false, false, false, null, constrDesc.source false, false, false, null, constrDesc.source
) )
} }
constrDesc.initialize(args, Visibilities.PUBLIC, targs) constrDesc.initialize(args, Visibilities.PUBLIC, typeParameters)
constrDesc.returnType = classDescriptor.defaultType constrDesc.returnType = classDescriptor.defaultType
return constrDesc return constrDesc
} }