Skip to content

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

@solonovamax

Description

@solonovamax

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"})

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions