Bytecode retains seemingly pointless `checkcast` instruction causing `VerifyError`
I'm attempting to run ProGuard 7.6.1 on my library's unit tests to assert they all still pass when the library is minified. My library depends on kotlinx.coroutines which contains code that ProGuard processes into an invalid state causing a VerifyError:
java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
kotlinx/coroutines/JobKt.invokeOnCompletion(Lkotlinx/coroutines/Job;ZLkotlinx/coroutines/JobNode;)Lkotlinx/coroutines/DisposableHandle; @40: invokeinterface
Reason:
Type 'kotlin/jvm/functions/Function1' (current frame, stack[3]) is not assignable to 'kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1'
Current Frame:
bci: @40
flags: { }
locals: { 'kotlinx/coroutines/Job', integer, 'kotlinx/coroutines/JobNode' }
stack: { 'kotlinx/coroutines/Job', integer, integer, 'kotlin/jvm/functions/Function1' }
Bytecode:
0000000: 2a1b 2c4d 3c59 4bc1 0007 9900 0d2a c000
0000010: 071b 2cb6 000a b02a 2cb6 0009 1bbb 0005
0000020: 592c b700 08c0 0002 b900 0b04 00b0
Stackmap Table:
same_frame(@23)
at kotlinx.coroutines.JobKt__JobKt.invokeOnCompletion$default$7beb268f(Job.kt:351)
at kotlinx.coroutines.CancellableContinuationImpl.installParentHandle(CancellableContinuationImpl.kt:23001)
at kotlinx.coroutines.CancellableContinuationImpl.initCancellability(CancellableContinuationImpl.kt:126)
at kotlinx.coroutines.DelayKt.delay-VtjQ1oo(Delay.kt:2178)
The offending bytecode is this:
29: new #5 // class kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1
32: dup
33: aload_2
34: invokespecial #8 // Method kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1."<init>":(Lkotlinx/coroutines/JobNode;)V
37: checkcast #2 // class kotlin/jvm/functions/Function1
40: invokeinterface #11, 4 // InterfaceMethod kotlinx/coroutines/Job.invokeOnCompletion$87b5a68:(ZZLkotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1;)Lkotlinx/coroutines/DisposableHandle;
Here we can see that the offending bytecode 40 is an invoke which accepts a type of kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1 but the bytecode prior, 37, is doing a cast to kotlin/jvm/functions/Function1 which causes the error:
Type 'kotlin/jvm/functions/Function1' (current frame, stack[3]) is not assignable to 'kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1'
The original function in kotlinx.coroutines uses the Function1 type for its parameter, and the anonymous $1 class does implement that interface. ProGuard seems to be lifting the parameter type to the sole implementation the method is invoked with, but failing to remove the now-needless and error-inducing checkcast.
A PR with the offending build setup is here: https://github.com/JakeWharton/mosaic/pull/591
If this is too difficult to run to debug in its current state (Gradle's build classpath), I'm happy to create an isolated project that reproduces.
Thanks for the report!
I was able to patch your PR and reproduce the issue locally. It indeed seems to be caused by the method/specialization/parametertype optimization not detecting the check cast right before that. If you need to unblock your pr, you can temporarily disable only that optimization with this rule:
-optimizations !method/specialization/parametertype
It solves the issue locally for me. Looking at what's going wrong, it seems we don't handle such cases in the MemberDescriptorSpecializer
Thanks! I'll use that workaround for now.