Description
The following code:
trait Semigroup[F] { self =>
def append(f1: F, f2: => F): F
val z = 10
}
object bug extends App {
case class Box(i: Int)
val boxSemigroup: Semigroup[Box] = (x1, x2) => Box(Math.max(x1.i, x2.i))
println(boxSemigroup.append(Box(1), Box(2)))
}
crashes at runtime with ClassCastException
Exception in thread "main" java.lang.ClassCastException: bug$Box cannot be cast to scala.Function0
at bug$$anonfun$1.append(bug.scala:75)
at bug$$anonfun$1.append(bug.scala:75)
at bug$.delayedEndpoint$bug$1(bug.scala:76)
at bug$delayedInit$body.apply(bug.scala:73)
at scala.Function0.apply$mcV$sp(Function0.scala:34)
at scala.Function0.apply$mcV$sp$(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App.$anonfun$main$1$adapted(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:389)
at scala.App.main(App.scala:76)
at scala.App.main$(App.scala:74)
at bug$.main(bug.scala:73)
at bug.main(bug.scala)
Seems like the bytecode generated contains erroneous call to function representing call-by-name argument (instruction at 2) and then casting of it's result to Function0 (instruction at 7):
public final bug$Box append(bug$Box, scala.Function0<bug$Box>);
Code:
0: aload_1
1: aload_2
2: invokeinterface #35, 1 // InterfaceMethod scala/Function0.apply:()Ljava/lang/Object;
7: checkcast #31 // class scala/Function0
10: invokestatic #38 // Method bug$.bug$$$anonfun$boxSemigroup$1:(Lbug$Box;Lscala/Function0;)Lbug$Box;
13: areturn
Also note that if name of call-by-name argument in trait and SAM implementation are the same as in:
trait Semigroup[F] { self =>
def append(f1: F, x2: => F): F
val z = 10
}
object bug extends App {
case class Box(i: Int)
val boxSemigroup: Semigroup[Box] = (x1, x2) => Box(Math.max(x1.i, x2.i))
println(boxSemigroup.append(Box(1), Box(2)))
}
then it works as expected and compiler generates correct bytecode for this function:
public final bug$Box append(bug$Box, scala.Function0<bug$Box>);
Code:
0: aload_1
1: aload_2
2: invokestatic #32 // Method bug$.bug$$$anonfun$boxSemigroup$1:(Lbug$Box;Lscala/Function0;)Lbug$Box;
5: areturn
Tried with Scala versions 2.12.7 and 2.13.0-M5.
Also seems like this issue is related to #10362 since same exception is being thrown at runtime and similar bytecode is being generated in both cases.