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:
@@ -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);
|
||||
}
|
||||
|
||||
+6
-3
@@ -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
|
||||
|
||||
+5
-21
@@ -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)
|
||||
|
||||
+16
-19
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -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)
|
||||
|
||||
+3
-1
@@ -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)
|
||||
|
||||
+30
-11
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user