Skip to content

Local lazy vals wrapper variables are not named in the bytecode #16209

Open
@ghost

Description

Compiler version

3.2.0

Comparing to Scala 2.13.10

object main {
  def main(args: Array[String]): Unit = {
    lazy val str = "abc"
    println(str)
  }
}

The main method compiles to the following bytecode:

  public void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=2
         0: new           #19                 // class scala/runtime/LazyRef
         3: dup
         4: invokespecial #20                 // Method scala/runtime/LazyRef."<init>":()V
         7: astore_2
         8: getstatic     #25                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
        11: aload_2
        12: invokestatic  #29                 // Method str$1:(Lscala/runtime/LazyRef;)Ljava/lang/String;
        15: invokevirtual #33                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        18: return
      LineNumberTable:
        line 3: 0
        line 4: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            8      11     2 str$lzy   Lscala/runtime/LazyRef;
            0      19     0  this   Lmain$;
            0      19     1  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args                           final

str$lzy is a scala.runtime.LazyRef local variable. This variable can be passed to the synthetic getter str$1 (signature: java.lang.String str$1(scala.runtime.LazyRef)) and the lazy value initialized.

Scala 3.2.0 bytecode

The exact same code is compiled in the following way:

  public void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=2
         0: new           #30                 // class scala/runtime/LazyRef
         3: dup
         4: invokespecial #31                 // Method scala/runtime/LazyRef."<init>":()V
         7: astore_2
         8: getstatic     #36                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
        11: aload_0
        12: aload_2
        13: invokespecial #40                 // Method str$1:(Lscala/runtime/LazyRef;)Ljava/lang/String;
        16: invokevirtual #44                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        19: return
      LineNumberTable:
        line 2: 0
        line 3: 0
        line 4: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      20     0  this   Lmain$;
            0      20     1  args   [Ljava/lang/String;
    Signature: #27                          // ([Ljava/lang/String;)V
    MethodParameters:
      Name                           Flags
      args                           final

where there is no entry for the scala.runtime.LazyRef wrapper variable.

If this variable is surfaced (like in Scala 2.13), additional debugger functionality can be built on top of it. For example, IDEA is able to present lazy values like the following:

Screen Shot 2022-10-19 at 10 37 22

And after initializing the lazy value on demand by clicking on the initialize prompt:

Screen Shot 2022-10-19 at 10 37 39

Thanks.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions