The Kotlin code compiled by Kotlin 2.0 with KotlinX serialization applied is executed with an error if ProGuard optimization is enabled.
Error
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
dev/mikchan/misc/ksp/model/Model$$serializer.<clinit>()V @38: putstatic
Reason:
Type 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor' (current frame, stack[0]) is not assignable to 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor'
Current Frame:
bci: @38
flags: { }
locals: { 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor' }
stack: { 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor' }
As an example, we can consider the class dev.mikchan.misc.ksp.model.Model$$serializer
The problem is in the <clinit> method
Original method bytecode
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=5, locals=1, args_size=0
0: new #2 // class dev/mikchan/misc/ksp/model/Model$$serializer
3: dup
4: invokespecial #144 // Method "<init>":()V
7: putstatic #146 // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
10: new #148 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor
13: dup
14: ldc #150 // String dev.mikchan.misc.ksp.model.Model
16: getstatic #146 // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
19: checkcast #7 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer
22: iconst_1
23: invokespecial #153 // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor."<init>":(Ljava/lang/String;Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer;I)V
26: astore_0
27: aload_0
28: ldc #155 // String lets
30: iconst_0
31: invokevirtual #159 // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.addElement:(Ljava/lang/String;Z)V
34: aload_0
35: checkcast #113 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor
38: putstatic #73 // Field descriptor:Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor;
41: return
LineNumberTable:
line 5: 10
line 6: 41
}
optimyzed bytecode
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=5, locals=1, args_size=0
0: new #7 // class dev/mikchan/misc/ksp/model/Model$$serializer
3: dup
4: invokespecial #24 // Method "<init>":()V
7: putstatic #20 // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
10: new #16 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor
13: dup
14: ldc #2 // String dev.mikchan.misc.ksp.model.Model
16: getstatic #20 // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
19: checkcast #15 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer
22: iconst_1
23: invokespecial #27 // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor."<init>":(Ljava/lang/String;Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer;I)V
26: dup
27: astore_0
28: ldc #3 // String lets
30: iconst_0
31: invokevirtual #28 // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.addElement:(Ljava/lang/String;Z)V
34: aload_0
35: checkcast #12 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor
38: putstatic #21 // Field descriptor$2e3cfc03:Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor;
41: return
LineNumberTable:
line 5: 10
line 6: 41
}
As you can see, the type of the descriptor field has changed from Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor; to Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor;
The problem goes away if you add the rule
-keepclassmembers public class **$$serializer {
private ** descriptor;
}
The Kotlin code compiled by Kotlin 2.0 with KotlinX serialization applied is executed with an error if ProGuard optimization is enabled.
Error
Reproducer
Reproducer project: https://github.com/wtlgo/Kotlin-Serialization-Proguard
To reproduce:
proguardJar
Gradle taskjava -jar build/libs/Kotlin-Serialization-Proguard-1.0-SNAPSHOT-pro.jar
Details
As an example, we can consider the class
dev.mikchan.misc.ksp.model.Model$$serializer
The problem is in the
<clinit>
methodOriginal method bytecode
optimyzed bytecode
As you can see, the type of the
descriptor
field has changed fromLdev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor;
toLdev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor;
The problem goes away if you add the rule