From 4bc521249bd2e4cc4f618253a5ecfa84fdf18df5 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Wed, 21 Jul 2021 10:06:12 +0000 Subject: [PATCH] kotlinx.serialization: Support InheritableSerialInfo --- .../backend/konan/CodeGenerationInfo.kt | 4 +- .../compiler/backend/ir/GeneratorHelpers.kt | 24 ++++++++- .../backend/ir/SerializerIrGenerator.kt | 3 +- .../diagnostic/SerializationErrors.java | 2 + .../SerializationPluginDeclarationChecker.kt | 30 ++++++++++++ .../SerializationPluginErrorsRendering.kt | 7 +++ .../SerializationResolveExtension.kt | 5 +- .../compiler/resolve/KSerializationUtil.kt | 8 ++- .../resolve/KSerializerDescriptorResolver.kt | 3 +- .../compiler/resolve/NamingConventions.kt | 2 + ...lizationPluginDiagnosticTestGenerated.java | 5 ++ .../testData/diagnostics/InheritableInfo.kt | 49 +++++++++++++++++++ 12 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/InheritableInfo.kt diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CodeGenerationInfo.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CodeGenerationInfo.kt index 309bdb56628..2233b9931d2 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CodeGenerationInfo.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CodeGenerationInfo.kt @@ -12,9 +12,11 @@ import org.jetbrains.kotlin.name.FqName internal fun IrClass.isNonGeneratedAnnotation(): Boolean = this.kind == ClassKind.ANNOTATION_CLASS && - !this.annotations.hasAnnotation(serialInfoAnnotationFqName) + !this.annotations.hasAnnotation(serialInfoAnnotationFqName) && + !this.annotations.hasAnnotation(inheritableSerialInfoFqName) private val serialInfoAnnotationFqName = FqName("kotlinx.serialization.SerialInfo") +private val inheritableSerialInfoFqName = FqName("kotlinx.serialization.InheritableSerialInfo") /** * We don't need to generate RTTI in some cases, e.g. Objective-C external classes. diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index 3d2839ab018..edcb5dd92bc 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.interpreter.toIrConst import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.* @@ -27,6 +28,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.resolve.BindingContext @@ -1096,7 +1098,7 @@ interface IrBuilderExtension { assert(ctor.isBound) val ctorDecl = ctor.owner if (needToCopyAnnotations) { - val classAnnotations = copyAnnotationsFrom(thisIrType.getClass()?.annotations.orEmpty()) + val classAnnotations = copyAnnotationsFrom(thisIrType.getClass()?.let { collectSerialInfoAnnotations(it) }.orEmpty()) args = args + createArrayOfExpression(compilerContext.irBuiltIns.annotationType, classAnnotations) } @@ -1105,6 +1107,26 @@ interface IrBuilderExtension { return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType) } + fun collectSerialInfoAnnotations(irClass: IrClass): List { + if (!(irClass.isInterface || irClass.descriptor.hasSerializableAnnotation)) return emptyList() + val annotationByFq: MutableMap = irClass.annotations.associateBy { it.symbol.owner.parentAsClass.descriptor.fqNameSafe }.toMutableMap() + for (clazz in irClass.getAllSuperclasses()) { + val annotations = clazz.annotations + .mapNotNull { + val descriptor = it.symbol.owner.parentAsClass.descriptor + if (descriptor.isInheritableSerialInfoAnnotation) descriptor.fqNameSafe to it else null + } + annotations.forEach { (fqname, call) -> + if (fqname !in annotationByFq) { + annotationByFq[fqname] = call + } else { + // SerializationPluginDeclarationChecker already reported inconsistency + } + } + } + return annotationByFq.values.toList() + } + fun IrBuilderWithScope.callSerializerFromCompanion( thisIrType: IrType, typeArgs: List, diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt index 54c18634d5f..7492d11dbbb 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue @@ -96,7 +95,7 @@ open class SerializerIrGenerator( addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS) // add class annotations copySerialInfoAnnotationsToDescriptor( - serializableIrClass.annotations, + collectSerialInfoAnnotations(serializableIrClass), localDesc, serialDescImplClass.referenceFunctionSymbol(CallingConventions.addClassAnnotation) ) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java index 7ab677384f7..d113a0d1fbb 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java @@ -40,6 +40,8 @@ public interface SerializationErrors { DiagnosticFactory3 REQUIRED_KOTLIN_TOO_HIGH = DiagnosticFactory3.create(ERROR); DiagnosticFactory3 PROVIDED_RUNTIME_TOO_LOW = DiagnosticFactory3.create(ERROR); + DiagnosticFactory2 INCONSISTENT_INHERITABLE_SERIALINFO = DiagnosticFactory2.create(ERROR); + @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt index af9d6371fe1..d5797a9a780 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt @@ -10,8 +10,11 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.KotlinCompilerVersion import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker @@ -51,6 +54,33 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker { checkCorrectTransientAnnotationIsUsed(descriptor, props.serializableProperties, context.trace) checkTransients(declaration, context.trace) analyzePropertiesSerializers(context.trace, descriptor, props.serializableProperties) + checkInheritedAnnotations(descriptor, declaration, context.trace) + } + + private fun checkInheritedAnnotations(descriptor: ClassDescriptor, declaration: KtDeclaration, trace: BindingTrace) { + val annotationsFilter: (Annotations) -> List> = { an -> + an.map { it.annotationClass!!.fqNameSafe to it } + .filter { it.second.annotationClass?.isInheritableSerialInfoAnnotation == true } + } + val annotationByFq: MutableMap = mutableMapOf() + val reported: MutableSet = mutableSetOf() + // my annotations + annotationByFq.putAll(annotationsFilter(descriptor.annotations)) + // inherited + for (clazz in descriptor.getAllSuperClassifiers()) { + val annotations = annotationsFilter(clazz.annotations) + annotations.forEach { (fqname, call) -> + if (fqname in annotationByFq) { + val existing = annotationByFq.getValue(fqname) + if (existing.allValueArguments != call.allValueArguments) { + if (reported.add(fqname)) { + val entry = (existing as? LazyAnnotationDescriptor)?.annotationEntry ?: declaration + trace.report(SerializationErrors.INCONSISTENT_INHERITABLE_SERIALINFO.on(entry, existing.type, clazz.defaultType)) + } + } + } + } + } } private fun checkMinRuntime(versions: VersionReader.RuntimeVersions, descriptor: ClassDescriptor, trace: BindingTrace) { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt index 255944a71dd..b090a0843bc 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt @@ -116,5 +116,12 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension { Renderers.STRING, Renderers.STRING ) + + MAP.put( + SerializationErrors.INCONSISTENT_INHERITABLE_SERIALINFO, + "Argument values for inheritable serial info annotation ''{0}'' must be the same as the values in parent type ''{1}''", + Renderers.RENDER_TYPE, + Renderers.RENDER_TYPE + ) } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt index ed757d48e60..079d2174310 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt @@ -21,12 +21,11 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProv import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.resolve.* -import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName import java.util.* open class SerializationResolveExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : SyntheticResolveExtension { override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List = when { - thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && thisDescriptor.platform?.isJvm() == true -> listOf(SerialEntityNames.IMPL_NAME) + thisDescriptor.isSerialInfoAnnotation && thisDescriptor.platform?.isJvm() == true -> listOf(SerialEntityNames.IMPL_NAME) (thisDescriptor.shouldHaveGeneratedSerializer) && !thisDescriptor.hasCompanionObjectAsSerializer -> listOf(SerialEntityNames.SERIALIZER_CLASS_NAME) else -> listOf() @@ -65,7 +64,7 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP declarationProvider: ClassMemberDeclarationProvider, result: MutableSet ) { - if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && name == SerialEntityNames.IMPL_NAME) + if (thisDescriptor.isSerialInfoAnnotation && name == SerialEntityNames.IMPL_NAME) result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx)) else if (thisDescriptor.shouldHaveGeneratedSerializer && name == SerialEntityNames.SERIALIZER_CLASS_NAME && result.none { it.name == SerialEntityNames.SERIALIZER_CLASS_NAME } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt index e2a42f0a98e..8cff6c1c3b2 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound +import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.inheritableSerialInfoFqName import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName internal fun isAllowedToHaveAutoGeneratedSerializerMethods( @@ -73,7 +74,10 @@ internal val DeclarationDescriptor.serializerForClass: KotlinType? get() = annotations.findAnnotationKotlinTypeValue(SerializationAnnotations.serializerAnnotationFqName, module, "forClass") internal val ClassDescriptor.isSerialInfoAnnotation: Boolean - get() = annotations.hasAnnotation(serialInfoFqName) + get() = annotations.hasAnnotation(serialInfoFqName) || annotations.hasAnnotation(inheritableSerialInfoFqName) + +internal val ClassDescriptor.isInheritableSerialInfoAnnotation: Boolean + get() = annotations.hasAnnotation(inheritableSerialInfoFqName) internal val Annotations.serialNameValue: String? get() = findAnnotationConstantValue(SerializationAnnotations.serialNameAnnotationFqName, "value") @@ -129,7 +133,7 @@ internal fun ClassDescriptor.enumEntries(): List { internal val Annotations.hasAnySerialAnnotation: Boolean get() = serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true } -private val ClassDescriptor.hasSerializableAnnotation +internal val ClassDescriptor.hasSerializableAnnotation get() = annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName) internal val ClassDescriptor.hasSerializableAnnotationWithoutArgs: Boolean diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt index c8954fa21ba..0aec7de2f50 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt @@ -33,7 +33,6 @@ import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDesc import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.IMPL_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_CLASS_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix -import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName import java.util.* object KSerializerDescriptorResolver { @@ -48,7 +47,7 @@ object KSerializerDescriptorResolver { fun isSerialInfoImpl(thisDescriptor: ClassDescriptor): Boolean { return thisDescriptor.name == IMPL_NAME && thisDescriptor.containingDeclaration is LazyClassDescriptor - && thisDescriptor.containingDeclaration.annotations.hasAnnotation(serialInfoFqName) + && (thisDescriptor.containingDeclaration as ClassDescriptor).isSerialInfoAnnotation } fun addSerialInfoSuperType(thisDescriptor: ClassDescriptor, supertypes: MutableList) { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt index 0cc4918ef1e..99124d55a5c 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt @@ -28,7 +28,9 @@ object SerializationAnnotations { internal val serialNameAnnotationFqName = FqName("kotlinx.serialization.SerialName") internal val requiredAnnotationFqName = FqName("kotlinx.serialization.Required") val serialTransientFqName = FqName("kotlinx.serialization.Transient") + // Also implicitly used in kotlin-native.compiler.backend.native/CodeGenerationInfo.kt internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo") + internal val inheritableSerialInfoFqName = FqName("kotlinx.serialization.InheritableSerialInfo") internal val encodeDefaultFqName = FqName("kotlinx.serialization.EncodeDefault") internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization") // this one is deprecated diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java index dce54ff1bf9..7d63ac83601 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java @@ -44,6 +44,11 @@ public class SerializationPluginDiagnosticTestGenerated extends AbstractSerializ runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient2.kt"); } + @TestMetadata("InheritableInfo.kt") + public void testInheritableInfo() throws Exception { + runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/InheritableInfo.kt"); + } + @TestMetadata("LazyRecursionBug.kt") public void testLazyRecursionBug() throws Exception { runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt"); diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/InheritableInfo.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/InheritableInfo.kt new file mode 100644 index 00000000000..b257dcc2611 --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/InheritableInfo.kt @@ -0,0 +1,49 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE +// WITH_RUNTIME +// SKIP_TXT +// !USE_EXPERIMENTAL: kotlinx.serialization.ExperimentalSerializationApi +// FILE: test.kt + +import kotlinx.serialization.* +import kotlin.reflect.KClass + +// TODO: for this test to work, runtime dependency should be updated to (yet unreleased) serialization 1.3.0 +//@InheritableSerialInfo +annotation class I(val value: String) + +enum class E { A, B } + +//@InheritableSerialInfo +annotation class I2(val e: E, val k: KClass<*>) + +@Serializable +@I("a") +sealed class Result { +// @I("b") + @Serializable class OK(val s: String): Result() +} + +@Serializable +@I("a") +@I2(E.A, E::class) +open class A + +@Serializable +@I("a") +@I2(E.A, E::class) +open class Correct: A() + +@Serializable +@I("a") +//@I2(E.B, E::class) +open class B: A() + +@Serializable +@I("a") +//@I2(E.A, I::class) +open class B2: A() + +@Serializable +//@I("b") +//@I2(E.A, E::class) +open class C: B() \ No newline at end of file