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) typeArgs = listOf(thisIrType)
} }
enumSerializerId -> { enumSerializerId -> {
serializerClass = module.getClassFromInternalSerializationPackage("CommonEnumSerializer") serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer)
args = kType.toClassDescriptor!!.let { enumDesc -> args = kType.toClassDescriptor!!.let { enumDesc ->
listOf( listOf(
irString(enumDesc.serialName()), irString(enumDesc.serialName()),
irCall(findEnumValuesMethod(enumDesc)), irCall(findEnumValuesMethod(enumDesc))
createArrayOfExpression(
compilerContext.irBuiltIns.stringType,
getEnumMembersNames(enumDesc).map { irString(it) }.toList()
)
) )
} }
typeArgs = listOf(thisIrType) 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.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPureClassOrObject 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.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -160,8 +161,16 @@ internal fun AbstractSerialGenerator.serializerInstance(
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!) ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
) )
serializerClass.classId == enumSerializerId -> listOf( 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( serializerClass.classId == objectSerializerId -> listOf(
JsStringLiteral(kType.serialName()), JsStringLiteral(kType.serialName()),
@@ -83,11 +83,11 @@ internal fun InstructionAdapter.genValidateProperty(index: Int, bitMaskAddress:
iconst(0) iconst(0)
} }
internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, message: String) { internal fun InstructionAdapter.genMissingFieldExceptionThrow(fieldName: String) {
anew(Type.getObjectType(exceptionClass)) anew(Type.getObjectType(serializationExceptionMissingFieldName))
dup() dup()
aconst(message) aconst(fieldName)
invokespecial(exceptionClass, "<init>", "(Ljava/lang/String;)V", false) invokespecial(serializationExceptionMissingFieldName, "<init>", "(Ljava/lang/String;)V", false)
checkcast(Type.getObjectType("java/lang/Throwable")) checkcast(Type.getObjectType("java/lang/Throwable"))
athrow() athrow()
} }
@@ -287,7 +287,16 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
val serialName = kType.serialName() val serialName = kType.serialName()
when (serializer.classId) { 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 // a special way to instantiate enum -- need a enum KClass reference
// GENERIC_ARGUMENT forces boxing in order to obtain KClass // GENERIC_ARGUMENT forces boxing in order to obtain KClass
aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)) aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
@@ -191,7 +191,7 @@ class SerializableCodegenImpl(
genValidateProperty(i, bitMaskOff(i)) genValidateProperty(i, bitMaskOff(i))
val nonThrowLabel = Label() val nonThrowLabel = Label()
ificmpne(nonThrowLabel) ificmpne(nonThrowLabel)
genExceptionThrow(serializationExceptionMissingFieldName, prop.name) genMissingFieldExceptionThrow(prop.name)
visitLabel(nonThrowLabel) visitLabel(nonThrowLabel)
// setting field // setting field
load(0, thisAsmType) load(0, thisAsmType)
@@ -406,11 +406,8 @@ open class SerializerCodegenImpl(
) )
if (!serializableDescriptor.isInternalSerializable) { if (!serializableDescriptor.isInternalSerializable) {
//validate all required (constructor) fields //validate all required (constructor) fields
val nonThrowLabel = Label()
val throwLabel = Label()
for ((i, property) in properties.serializableConstructorProperties.withIndex()) { for ((i, property) in properties.serializableConstructorProperties.withIndex()) {
if (property.optional || property.transient) { if (property.optional || property.transient) {
// todo: Normal reporting of error
if (!property.isConstructorParameterWithDefault) if (!property.isConstructorParameterWithDefault)
throw CompilationException( throw CompilationException(
"Property ${property.name} was declared as optional/transient but has no default value", "Property ${property.name} was declared as optional/transient but has no default value",
@@ -419,15 +416,12 @@ open class SerializerCodegenImpl(
) )
} else { } else {
genValidateProperty(i, bitMaskOff(i)) genValidateProperty(i, bitMaskOff(i))
// todo: print name of each variable? val nonThrowLabel = Label()
ificmpeq(throwLabel) 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 // create object with constructor
anew(serializableAsmType) anew(serializableAsmType)
@@ -564,7 +558,7 @@ open class SerializerCodegenImpl(
// throw // throw
// set // set
ificmpne(nextLabel) ificmpne(nextLabel)
genExceptionThrow(serializationExceptionMissingFieldName, property.name) genMissingFieldExceptionThrow(property.name)
visitLabel(nextLabel) visitLabel(nextLabel)
} }
@@ -57,7 +57,8 @@ class SerializerForEnumsCodegen(
// regular .serialName() produces fqName here, which is kinda inconvenient for enum entry // regular .serialName() produces fqName here, which is kinda inconvenient for enum entry
val serialName = entry.annotations.serialNameValue ?: entry.name.toString() val serialName = entry.annotations.serialNameValue ?: entry.name.toString()
aconst(serialName) 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 // pushing annotations
addSyntheticAnnotationsToDescriptor(descriptorVar, entry, CallingConventions.addAnnotation) addSyntheticAnnotationsToDescriptor(descriptorVar, entry, CallingConventions.addAnnotation)
} }