Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decompilation failure with kotlin crossinline lambdas crossinlined into a suspending context #470

Open
solonovamax opened this issue Mar 10, 2025 · 0 comments

Comments

@solonovamax
Copy link

Vineflower version

1.11.1

Describe the bug

Vineflower cannot decompile kotlin crossinline lambdas when they are passed to a function which takes a suspending lambda.

Additional information

Here is some code which reproduces the issue. I have minimized it as much as possible, and have not been successful in minimizing it any further.

fun test() {
    return test2 { }
}

inline fun test2(crossinline fn: () -> Unit) {
    return runBlocking { fn() }
}

Here is the stack trace:

ERROR: Class ca/solostudios/nyx/plugin/compile/TestKt$test$$inlined$test2$1 couldn't be fully decompiled.
java.lang.IllegalStateException: Couldn't find method <anonymous> (Lkotlinx/coroutines/CoroutineScope;)V in class ca/solostudios/nyx/plugin/compile/TestKt$test$$inlined$test2$1
	at org.vineflower.kotlin.struct.KFunction.parse(KFunction.java:112)
	at org.vineflower.kotlin.KotlinWriter.writeClass(KotlinWriter.java:221)
	at org.jetbrains.java.decompiler.main.ClassesProcessor.writeClass(ClassesProcessor.java:500)
	at org.jetbrains.java.decompiler.main.Fernflower.getClassContent(Fernflower.java:196)
	at org.jetbrains.java.decompiler.struct.ContextUnit.lambda$save$3(ContextUnit.java:195)
	at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1403)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

If you run javap on the .class file, this is what it emits:

public final class ca.solostudios.nyx.plugin.compile.TestKt$test$$inlined$test2$1 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>, java.lang.Object> {
  int label;

  public ca.solostudios.nyx.plugin.compile.TestKt$test$$inlined$test2$1(kotlin.coroutines.Continuation);
    Code:
       0: aload_0
       1: iconst_2
       2: aload_1
       3: invokespecial #19                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V
       6: return

  public final java.lang.Object invokeSuspend(java.lang.Object);
    Code:
       0: invokestatic  #42                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;
       3: pop
       4: aload_0
       5: getfield      #44                 // Field label:I
       8: tableswitch   { // 0 to 0
                     0: 28
               default: 39
          }
      28: aload_1
      29: invokestatic  #50                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
      32: iconst_0
      33: istore_2
      34: nop
      35: getstatic     #56                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
      38: areturn
      39: new           #58                 // class java/lang/IllegalStateException
      42: dup
      43: ldc           #60                 // String call to \'resume\' before \'invoke\' with coroutine
      45: invokespecial #63                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
      48: athrow

  public final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);
    Code:
       0: new           #2                  // class ca/solostudios/nyx/plugin/compile/TestKt$test$$inlined$test2$1
       3: dup
       4: aload_2
       5: invokespecial #71                 // Method "<init>":(Lkotlin/coroutines/Continuation;)V
       8: checkcast     #73                 // class kotlin/coroutines/Continuation
      11: areturn

  public final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);
    Code:
       0: aload_0
       1: aload_1
       2: aload_2
       3: invokevirtual #80                 // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
       6: checkcast     #2                  // class ca/solostudios/nyx/plugin/compile/TestKt$test$$inlined$test2$1
       9: getstatic     #56                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
      12: invokevirtual #82                 // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
      15: areturn

  public java.lang.Object invoke(java.lang.Object, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #86                 // class kotlinx/coroutines/CoroutineScope
       5: aload_2
       6: checkcast     #73                 // class kotlin/coroutines/Continuation
       9: invokevirtual #88                 // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
      12: areturn
}

and here are the kotlin annotations at the top of the class (decompiled with fernflower to get them):

@DebugMetadata(
   f = "test.kt",
   l = {},
   i = {},
   s = {},
   n = {},
   m = "invokeSuspend",
   c = "ca.solostudios.nyx.plugin.compile.TestKt$test$$inlined$test2$1"
)
@Metadata(
   mv = {1, 8, 0},
   k = 3,
   xi = 48,
   d1 = {"\u0000\f\n\u0000\n\u0002\u0010\u0002\n\u0002\u0018\u0002\n\u0000\u0010\u0000\u001a\u00020\u0001*\u00020\u0002H\u008a\u0006\u0003"},
   d2 = {"<anonymous>", "", "Lkotlinx/coroutines/CoroutineScope;", "ca/solostudios/nyx/plugin/compile/TestKt$test2$1"}
)
@SourceDebugExtension({"SMAP\ntest.kt\nKotlin\n*S Kotlin\n*F\n+ 1 test.kt\nca/solostudios/nyx/plugin/compile/TestKt$test2$1\n+ 2 test.kt\nca/solostudios/nyx/plugin/compile/TestKt\n*L\n1#1,37:1\n33#2:38\n*E\n"})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant