-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
I saw this in some cats effect code when using resources. I minimised it to the code below.
Compiler version
3.7.4
Minimized code
package app
object Example:
private class Wrapper[A](value: A):
def use[B](f: A => B): B = f(value)
end Wrapper
def run: Int =
val tupleWrapper = Wrapper((42, "Answer"))
// tupleWrapper.use { case (number, _) => number }
tupleWrapper.use { (number, _) => number }
end run
end ExampleOutput
When using the case for the inner lambda the code produced for it is this:
private final static synthetic run$$anonfun$1(Lscala/Tuple2;)I
// parameter final x$1
L0
LINENUMBER 12 L0
ALOAD 0
ASTORE 1
ALOAD 1
INVOKEVIRTUAL scala/Tuple2._1 ()Ljava/lang/Object;
INVOKESTATIC scala/runtime/BoxesRunTime.unboxToInt (Ljava/lang/Object;)I
ISTORE 2
L1
ILOAD 2
IRETURNwhich is what one would expect. Only the first element of the pair is referenced since it is the only one used. But when the case keyword is not there (in which case automatic untupling takes place), we get the following:
private final static synthetic run$$anonfun$1(Lscala/Tuple2;)I
// parameter final x$1
L0
LINENUMBER 12 L0
ALOAD 0
INVOKEVIRTUAL scala/Tuple2._1 ()Ljava/lang/Object;
INVOKESTATIC scala/runtime/BoxesRunTime.unboxToInt (Ljava/lang/Object;)I
ISTORE 1
L1
ALOAD 0
INVOKEVIRTUAL scala/Tuple2._2 ()Ljava/lang/Object;
CHECKCAST java/lang/String
ASTORE 2
L2
ILOAD 1
IRETURNAs you can see now we fetch the second unused elements of the pair and we do a CHECKCAST on it (and so the JVM cannot remove references to it, since CHECKCAST is side-effecting -- throws exceptions). If you had 10 ignored args you get 10 CHECKCAST instructions.
Expectation
I would expect to get the same code in both cases. In the words of @som-snytt why is it that can't we have nice things...