Skip to content

Conversation

@Godin
Copy link
Member

@Godin Godin commented Nov 23, 2024

For Example.kt

sealed class Sealed {
    object Sealed1 : Sealed()
    object Sealed2 : Sealed()
}

fun example(sealed: Sealed) {
    when (sealed) {
        is Sealed.Sealed1 -> println("case 1")
        is Sealed.Sealed2 -> println("case 2")
    }
}

fun main() {
    example(Sealed.Sealed1)
    example(Sealed.Sealed2)
}

Using Kotlin compiler version 2.0.0 execution of

kotlin-compiler-2.0.0/bin/kotlinc Example.kt -d classes

javap -v -p classes/ExampleKt.class

java \
    -javaagent:jacoco-0.8.12/lib/jacocoagent.jar \
    -cp kotlin-compiler-2.0.0/lib/kotlin-stdlib.jar:classes \
    ExampleKt

java \
     -jar jacoco-0.8.12/lib/jacococli.jar \
     report jacoco.exec \
     --classfiles classes \
     --sourcefiles . \
     --html report

produces

Screenshot 2024-11-23 at 15 33 12 Screenshot 2024-11-23 at 15 33 30
  public static final void example(Sealed);
    descriptor: (LSealed;)V
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: ldc           #9                  // String s
         3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
         6: aload_0
         7: astore_1
         8: aload_1
         9: instanceof    #17                 // class Sealed$Sealed1
        12: ifeq          27
        15: ldc           #19                 // String case 1
        17: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        20: swap
        21: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        24: goto          54
        27: aload_1
        28: instanceof    #33                 // class Sealed$Sealed2
        31: ifeq          46
        34: ldc           #35                 // String case 2
        36: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        39: swap
        40: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        43: goto          54
        46: new           #37                 // class kotlin/NoWhenBranchMatchedException
        49: dup
        50: invokespecial #41                 // Method kotlin/NoWhenBranchMatchedException."<init>":()V
        53: athrow
        54: return

Whereas using Kotlin compiler version 1.9.23

Screenshot 2024-11-23 at 15 31 49 Screenshot 2024-11-23 at 15 32 26
  public static final void example(Sealed);
    descriptor: (LSealed;)V
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: ldc           #9                  // String s
         3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
         6: aload_0
         7: astore_1
         8: aload_1
         9: instanceof    #17                 // class Sealed$Sealed1
        12: ifeq          27
        15: ldc           #19                 // String case 1
        17: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        20: swap
        21: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        24: goto          43
        27: aload_1
        28: instanceof    #33                 // class Sealed$Sealed2
        31: ifeq          43
        34: ldc           #35                 // String case 2
        36: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        39: swap
        40: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        43: return

which was indistinguishable from bytecode produced for

abstract class NonSealed {
    class NonSealed1 : NonSealed()
    class NonSealed2 : NonSealed()
    class NonSealed3 : NonSealed()
}

fun example1(nonSealed: NonSealed) {
    when (nonSealed) {
        is NonSealed.NonSealed1 -> println("case 1")
        is NonSealed.NonSealed2 -> println("case 2")
    }
}

fun example2(nonSealed: NonSealed) {
    if (nonSealed is NonSealed.NonSealed1) println("case 1")
    else if (nonSealed is NonSealed.NonSealed2) println("case 2")
}

fun main() {
    example1(NonSealed.NonSealed1())
    example1(NonSealed.NonSealed2())

    example2(NonSealed.NonSealed1())
    example2(NonSealed.NonSealed2())
}
  public static final void example1(NonSealed);
    descriptor: (LNonSealed;)V
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: ldc           #9                  // String nonSealed
         3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
         6: aload_0
         7: astore_1
         8: aload_1
         9: instanceof    #17                 // class NonSealed$NonSealed1
        12: ifeq          27
        15: ldc           #19                 // String case 1
        17: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        20: swap
        21: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        24: goto          43
        27: aload_1
        28: instanceof    #33                 // class NonSealed$NonSealed2
        31: ifeq          43
        34: ldc           #35                 // String case 2
        36: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        39: swap
        40: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        43: return

  public static final void example2(NonSealed);
    descriptor: (LNonSealed;)V
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: ldc           #9                  // String nonSealed
         3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
         6: aload_0
         7: instanceof    #17                 // class NonSealed$NonSealed1
        10: ifeq          25
        13: ldc           #19                 // String case 1
        15: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        18: swap
        19: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        22: goto          41
        25: aload_0
        26: instanceof    #33                 // class NonSealed$NonSealed2
        29: ifeq          41
        32: ldc           #35                 // String case 2
        34: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
        37: swap
        38: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        41: return

Closes #1219

@Godin Godin force-pushed the kotlin_when_sealed_statement branch from 4d94737 to c8d7573 Compare November 24, 2024 20:15
@Godin Godin marked this pull request as ready for review November 24, 2024 20:16
@Godin Godin requested a review from leveretka November 24, 2024 20:16
@Godin Godin enabled auto-merge (squash) November 24, 2024 20:42
@Godin Godin merged commit 1070551 into jacoco:master Nov 24, 2024
33 checks passed
@Godin Godin deleted the kotlin_when_sealed_statement branch November 24, 2024 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Missing branch coverage while using Sealed Classes

2 participants