Fix incorrect class reference in polymorphic and contextual case

Upper bound should be used for type parameters there
This commit is contained in:
Leonid Startsev
2022-08-08 13:15:06 +02:00
committed by Space
parent 6a6b542ae2
commit b17ead97bc
4 changed files with 24 additions and 37 deletions
@@ -379,11 +379,11 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
when (serializerClassOriginal.owner.classId) {
polymorphicSerializerId -> {
needToCopyAnnotations = true
args = listOf(classReference(kType))
args = listOf(classReference(kType.classOrUpperBound()!!))
typeArgs = listOf(thisIrType)
}
contextSerializerId -> {
args = listOf(classReference(kType))
args = listOf(classReference(kType.classOrUpperBound()!!))
typeArgs = listOf(thisIrType)
val hasNewCtxSerCtor = compilerContext.referenceConstructors(contextSerializerId).any { it.owner.valueParameters.size == 3 }
@@ -412,16 +412,16 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
}
objectSerializerId -> {
needToCopyAnnotations = true
args = listOf(irString(kType.serialName()), irGetObject(kType.classOrNull!!))
args = listOf(irString(kType.serialName()), irGetObject(kType.classOrUpperBound()!!))
typeArgs = listOf(thisIrType)
}
sealedSerializerId -> {
needToCopyAnnotations = true
args = mutableListOf<IrExpression>().apply {
add(irString(kType.serialName()))
add(classReference(kType))
add(classReference(kType.classOrUpperBound()!!))
val (subclasses, subSerializers) = allSealedSerializableSubclassesFor(
kType.classOrNull!!.owner,
kType.classOrUpperBound()!!.owner,
pluginContext
)
val projectedOutCurrentKClass =
@@ -431,7 +431,7 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
add(
createArrayOfExpression(
projectedOutCurrentKClass,
subclasses.map { classReference(it) }
subclasses.map { classReference(it.classOrUpperBound()!!) }
)
)
add(
@@ -528,7 +528,7 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
}
// If KType is interface, .classSerializer always yields PolymorphicSerializer, which may be unavailable for interfaces from other modules
if (!kType.isInterface() && serializerClassOriginal == kType.classOrNull!!.owner.classSerializer(pluginContext) && this@BaseIrGenerator !is SerializableCompanionIrGenerator) {
if (!kType.isInterface() && serializerClassOriginal == kType.classOrUpperBound()?.owner.classSerializer(pluginContext) && this@BaseIrGenerator !is SerializableCompanionIrGenerator) {
// This is default type serializer, we can shortcut through Companion.serializer()
// BUT not during generation of this method itself
callSerializerFromCompanion(thisIrType, typeArgs, args)?.let { return it }
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
@@ -506,8 +507,8 @@ interface IrBuilderWithPluginContext {
)
}
fun IrBuilderWithScope.classReference(classSymbol: IrType): IrClassReference =
createClassReference(classSymbol, startOffset, endOffset)
fun IrBuilderWithScope.classReference(classSymbol: IrClassSymbol): IrClassReference =
createClassReference(classSymbol.starProjectedType, startOffset, endOffset)
fun collectSerialInfoAnnotations(irClass: IrClass): List<IrConstructorCall> {
if (!(irClass.isInterface || irClass.descriptor.hasSerializableOrMetaAnnotation)) return emptyList()
@@ -555,14 +556,15 @@ interface IrBuilderWithPluginContext {
if (compilerContext.platform.isJvm()) {
// "Byte::class" -> "java.lang.Byte::class"
// TODO: get rid of descriptor
val wrapperFqName = KotlinBuiltIns.getPrimitiveType(classType.classOrNull!!.descriptor)?.let(JvmPrimitiveType::get)?.wrapperFqName
val wrapperFqName =
KotlinBuiltIns.getPrimitiveType(classType.classOrNull!!.descriptor)?.let(JvmPrimitiveType::get)?.wrapperFqName
if (wrapperFqName != null) {
val wrapperClass = compilerContext.referenceClass(ClassId.topLevel(wrapperFqName))
?: error("Primitive wrapper class for $classType not found: $wrapperFqName")
return classReference(wrapperClass.defaultType)
return createClassReference(wrapperClass.defaultType, startOffset, endOffset)
}
}
return classReference(classType)
return createClassReference(classType, startOffset, endOffset)
}
fun IrClass.getSuperClassOrAny(): IrClass = getSuperClassNotAny() ?: compilerContext.irBuiltIns.anyClass.owner
@@ -6,6 +6,7 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.jvm.ir.getStringConstArgument
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
@@ -108,7 +110,7 @@ internal fun IrClass.isSerializableEnum(): Boolean = kind == ClassKind.ENUM_CLAS
internal val IrType.genericIndex: Int?
get() = (this.classifierOrNull as? IrTypeParameterSymbol)?.owner?.index
fun IrType.serialName(): String = this.classOrNull!!.owner.serialName()
fun IrType.serialName(): String = this.classOrUpperBound()!!.owner.serialName()
fun IrClass.serialName(): String {
return annotations.serialNameValue ?: fqNameWhenAvailable?.asString() ?: error("${this.render()} does not have fqName")
@@ -199,4 +201,11 @@ fun findSerializerConstructorForTypeArgumentsSerializers(serializer: IrClass): I
return serializer.constructors.singleOrNull {
it.valueParameters.let { vps -> vps.size == typeParamsCount && vps.all { vp -> vp.type.isKSerializer() } }
}?.symbol
}
fun IrType.classOrUpperBound(): IrClassSymbol? = when(val cls = classifierOrNull) {
is IrClassSymbol -> cls
is IrScriptSymbol -> cls.owner.targetClass
is IrTypeParameterSymbol -> cls.owner.representativeUpperBound.classOrUpperBound()
else -> null
}
@@ -63,28 +63,4 @@ fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner
}.also {
it.containingClassForStaticMemberAttr = lookupTag
}
}
// FIXME: copied from Parcelize plugin
inline fun FirSession.createFunction(
owner: FirRegularClassSymbol,
callableId: CallableId,
init: FirSimpleFunctionBuilder.() -> Unit
): FirNamedFunctionSymbol {
val function = buildSimpleFunction {
moduleData = this@createFunction.moduleData
origin = SerializationPluginKey.origin
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
if (owner.modality == Modality.FINAL) Modality.FINAL else Modality.OPEN,
EffectiveVisibility.Public
).apply {
isOverride = true
}
name = callableId.callableName
symbol = FirNamedFunctionSymbol(callableId)
dispatchReceiverType = owner.defaultType()
init()
}
return function.symbol
}