Menu

#718 Kotlin nested lambdas are stripped

v6.0
open-later
None
Medium
2018-08-05
2018-08-01
No

Referencing https://discuss.kotlinlang.org/t/proguard-cant-process-this-simple-code/7054

Proguard fails to optizime the following code in Kotlin.

This seems to be a pattern that pops up in Kotlin based Android apps, or at least did for me the other day. I worked around this fairly easily with a helper method, but definitely unfortunate.

main.kt

fun main(args: Array<String>) {
  Error().run()
}

error.kt

class Error {
  fun run() {
    with(TestEnum.CASE) {
      runLambda {
        runLambda {
          println("Hello, World!")
        }
      }
    }
  }
  private fun runLambda(lambda: () -> Unit) = lambda()
}
enum class TestEnum {
  CASE
}


// Alternatively even more simply
/*
class Error {
  fun run() {
    with(Unit) {
      runLambda {
        runLambda {
          println("Hello, World!")
        }
      }
    }
  }
  private fun runLambda(lambda: () -> Unit) = lambda()
}
*/

myconfig.pro

-injars       proguard-bug.jar 
-outjars      proguard-bug_out.jar
-libraryjars <java.home>/lib/rt.jar

-keep public class MainKt { 
    public static void main(java.lang.String[]); 
}

-keep class org.jetbrains.annotations.** {
    public protected *;
}

-keep class kotlin.** {
    public protected *;
}
-dontnote kotlin.internal.PlatformImplementationsKt
-keepattributes Signature
-dontnote kotlin.reflect.jvm.internal.**

Compile instructions + Expected result

kotlinc . -include-runtime -d proguard-bug.jar
java -jar proguard-bug.jar
# Hello world!
./proguard6.0.3/bin/proguard.sh @myconfig.pro
# ...
# Warning: Error$run$1$1$1: can't find referenced class Error$run$1$1
# Warning: Error$run$1$1$1: can't find referenced class Error$run$1$1
# ...

Discussion

  • Nick Firmani

    Nick Firmani - 2018-08-01

    Kotlin version 1.2.51
    Java version 1.8.0_172
    ProGuard version 6.0.3

     
  • Eric Lafortune

    Eric Lafortune - 2018-08-05

    Thanks for your report. The class Error$run$1$1$1 in the compiled Kotlin code references a class Error$run$1$1 which is not present. The reference is from a constant that is not actually used in the code, so technically the compiled code is valid. However, ProGuard tries to resolve all references before finding out that the constant is not used (and removing it). Hopefully the Kotlin compiler will clean up its generated code somewhat in the future. For the time being, you can work around it by letting ProGuard accept the missing reference:

    -dontwarn Error$run$1$1
    

    You can use wildcards if you have many such cases.

    It's not necessary to explicitly preserve the Jetbrains annotations or Kotlin runtime in your configuration.

     
  • Eric Lafortune

    Eric Lafortune - 2018-08-05
    • status: open --> open-later
    • assigned_to: Eric Lafortune
     

Log in to post a comment.

MongoDB Logo MongoDB