Refactor plugin-generated call to EnumSerializer():

support new values() argument.
Get rid of old @JvmOverloads requirements in runtime.
This commit is contained in:
Leonid Startsev
2020-01-15 16:49:07 +03:00
parent 94ec22762a
commit 9558538d15
6 changed files with 35 additions and 26 deletions
@@ -588,15 +588,11 @@ interface IrBuilderExtension {
typeArgs = listOf(thisIrType)
}
enumSerializerId -> {
serializerClass = module.getClassFromInternalSerializationPackage("CommonEnumSerializer")
serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer)
args = kType.toClassDescriptor!!.let { enumDesc ->
listOf(
irString(enumDesc.serialName()),
irCall(findEnumValuesMethod(enumDesc)),
createArrayOfExpression(
compilerContext.irBuiltIns.stringType,
getEnumMembersNames(enumDesc).map { irString(it) }.toList()
)
irCall(findEnumValuesMethod(enumDesc))
)
}
typeArgs = listOf(thisIrType)
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType
@@ -160,8 +161,16 @@ internal fun AbstractSerialGenerator.serializerInstance(
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
)
serializerClass.classId == enumSerializerId -> listOf(
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!),
JsStringLiteral(kType.serialName())
JsStringLiteral(kType.serialName()),
// EnumClass.values() invocation
JsInvocation(
context.getInnerNameForDescriptor(
DescriptorUtils.getFunctionByName(
kType.toClassDescriptor!!.staticScope,
DescriptorUtils.ENUM_VALUES
)
).makeRef()
)
)
serializerClass.classId == objectSerializerId -> listOf(
JsStringLiteral(kType.serialName()),
@@ -83,11 +83,11 @@ internal fun InstructionAdapter.genValidateProperty(index: Int, bitMaskAddress:
iconst(0)
}
internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, message: String) {
anew(Type.getObjectType(exceptionClass))
internal fun InstructionAdapter.genMissingFieldExceptionThrow(fieldName: String) {
anew(Type.getObjectType(serializationExceptionMissingFieldName))
dup()
aconst(message)
invokespecial(exceptionClass, "<init>", "(Ljava/lang/String;)V", false)
aconst(fieldName)
invokespecial(serializationExceptionMissingFieldName, "<init>", "(Ljava/lang/String;)V", false)
checkcast(Type.getObjectType("java/lang/Throwable"))
athrow()
}
@@ -287,7 +287,16 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
val serialName = kType.serialName()
when (serializer.classId) {
enumSerializerId, contextSerializerId, polymorphicSerializerId -> {
enumSerializerId -> {
aconst(serialName)
signature.append("Ljava/lang/String;")
val enumJavaType = codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
invokestatic(enumJavaType.internalName, "values","()[${enumJavaType.descriptor}", false)
checkcast(javaEnumArray)
signature.append(javaEnumArray.descriptor)
}
contextSerializerId, polymorphicSerializerId -> {
// a special way to instantiate enum -- need a enum KClass reference
// GENERIC_ARGUMENT forces boxing in order to obtain KClass
aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
@@ -191,7 +191,7 @@ class SerializableCodegenImpl(
genValidateProperty(i, bitMaskOff(i))
val nonThrowLabel = Label()
ificmpne(nonThrowLabel)
genExceptionThrow(serializationExceptionMissingFieldName, prop.name)
genMissingFieldExceptionThrow(prop.name)
visitLabel(nonThrowLabel)
// setting field
load(0, thisAsmType)
@@ -406,11 +406,8 @@ open class SerializerCodegenImpl(
)
if (!serializableDescriptor.isInternalSerializable) {
//validate all required (constructor) fields
val nonThrowLabel = Label()
val throwLabel = Label()
for ((i, property) in properties.serializableConstructorProperties.withIndex()) {
if (property.optional || property.transient) {
// todo: Normal reporting of error
if (!property.isConstructorParameterWithDefault)
throw CompilationException(
"Property ${property.name} was declared as optional/transient but has no default value",
@@ -419,15 +416,12 @@ open class SerializerCodegenImpl(
)
} else {
genValidateProperty(i, bitMaskOff(i))
// todo: print name of each variable?
ificmpeq(throwLabel)
val nonThrowLabel = Label()
ificmpne(nonThrowLabel)
genMissingFieldExceptionThrow(property.name)
visitLabel(nonThrowLabel)
}
}
goTo(nonThrowLabel)
// throwing an exception
visitLabel(throwLabel)
genExceptionThrow(serializationExceptionName, "Not all required constructor fields were specified")
visitLabel(nonThrowLabel)
}
// create object with constructor
anew(serializableAsmType)
@@ -564,7 +558,7 @@ open class SerializerCodegenImpl(
// throw
// set
ificmpne(nextLabel)
genExceptionThrow(serializationExceptionMissingFieldName, property.name)
genMissingFieldExceptionThrow(property.name)
visitLabel(nextLabel)
}
@@ -57,7 +57,8 @@ class SerializerForEnumsCodegen(
// regular .serialName() produces fqName here, which is kinda inconvenient for enum entry
val serialName = entry.annotations.serialNameValue ?: entry.name.toString()
aconst(serialName)
invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;)V", false)
iconst(0)
invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;Z)V", false)
// pushing annotations
addSyntheticAnnotationsToDescriptor(descriptorVar, entry, CallingConventions.addAnnotation)
}