package variant
object Variant {
sealed trait ValueType
case object ByteValue extends ValueType
case object ShortValue extends ValueType
case object IntValue extends ValueType
case object LongValue extends ValueType
trait Unwrapper[@specialized(Byte, Short, Int, Long) P] {
def unwrap(v: Variant): P = v.value.asInstanceOf[P]
}
def apply(value: Byte): Variant = Variant(value, ByteValue)
def apply(value: Short): Variant = Variant(value, ShortValue)
def apply(value: Int): Variant = Variant(value, IntValue)
def apply(value: Long): Variant = Variant(value, LongValue)
}
case class Variant(value: Long, valueType: Variant.ValueType)
package variant
import variant.Variant.Unwrapper
object Main extends App with Unwrapper[Byte] {
val v = Variant(42.toByte)
val result = unwrap(v)
println(result)
}
--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Could you post the exception message and stack trace and mark where in the code it is thrown? Thanks!
trait Unwrapper[@specialized(Byte) P] {
def unwrap: P = {
val result = 0L.asInstanceOf[P]
result
}
}
object UnwrapperTest extends App with Unwrapper[Byte] {
println(unwrap)
}
With Scala 2.11.8 I get the following byte code:
$ javap -c Unwrapper
Compiled from "Unwrapper.scala"
public interface variant.Unwrapper{
public abstract java.lang.Object unwrap();
public abstract byte unwrap$mcB$sp();
}
$ javap -c Unwrapper\$class
Compiled from "Unwrapper.scala"
public abstract class variant.Unwrapper$class extends java.lang.Object{
public static java.lang.Object unwrap(variant.Unwrapper);
Code:
0: lconst_0
1: invokestatic #13; //Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
4: astore_1
5: aload_1
6: areturn
public static byte unwrap$mcB$sp(variant.Unwrapper);
Code:
0: aload_0
1: invokeinterface #24, 1; //InterfaceMethod variant/Unwrapper.unwrap:()Ljava/lang/Object;
6: invokestatic #28; //Method scala/runtime/BoxesRunTime.unboxToByte:(Ljava/lang/Object;)B
9: ireturn
public static void $init$(variant.Unwrapper);
Code:
0: return
}
$ javap -c Unwrapper\$mcB\$sp
Compiled from "Unwrapper.scala"
public interface variant.Unwrapper$mcB$sp extends variant.Unwrapper{
public abstract byte unwrap();
public abstract byte unwrap$mcB$sp();
}
$ javap -c Unwrapper\$mcB\$sp\$class
Compiled from "Unwrapper.scala"
public abstract class variant.Unwrapper$mcB$sp$class extends java.lang.Object{
public static byte unwrap(variant.Unwrapper$mcB$sp);
Code:
0: aload_0
1: invokeinterface #13, 1; //InterfaceMethod variant/Unwrapper$mcB$sp.unwrap$mcB$sp:()B
6: ireturn
public static byte unwrap$mcB$sp(variant.Unwrapper$mcB$sp);
Code:
0: lconst_0
1: l2i
2: i2b
3: istore_1
4: iload_1
5: ireturn
public static void $init$(variant.Unwrapper$mcB$sp);
Code:
0: return
}
With Scala 2.12.1 I get:
javap -c Unwrapper
public interface variant.Unwrapper{
public static java.lang.Object unwrap$(variant.Unwrapper);
Code:
0: aload_0
1: invokespecial #16; //InterfaceMethod unwrap:()Ljava/lang/Object;
4: areturn
public java.lang.Object unwrap();
Code:
0: lconst_0
1: invokestatic #23; //Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
4: astore_1
5: aload_1
6: areturn
public static byte unwrap$mcB$sp$(variant.Unwrapper);
Code:
0: aload_0
1: invokespecial #32; //InterfaceMethod unwrap$mcB$sp:()B
4: ireturn
public byte unwrap$mcB$sp();
Code:
0: aload_0
1: invokeinterface #16, 1; //InterfaceMethod unwrap:()Ljava/lang/Object;
6: invokestatic #36; //Method scala/runtime/BoxesRunTime.unboxToByte:(Ljava/lang/Object;)B
9: ireturn
public static void $init$(variant.Unwrapper);
Code:
0: return
javap -c Unwrapper\$mcB\$sp
public interface variant.Unwrapper$mcB$sp extends variant.Unwrapper{
}
I am not an expert on Java bytecode, but with Scala 2.11.8 I see the following byte code that converts a long to a byte:
public static byte unwrap$mcB$sp(variant.Unwrapper$mcB$sp);
Code:
0: lconst_0
1: l2i
2: i2b
3: istore_1
4: iload_1
5: ireturn
With Scala 2.12.1 I see no such code. Instead the following code is invoked:
public java.lang.Object unwrap();
Code:
0: lconst_0
1: invokestatic #23; //Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
4: astore_1
5: aload_1
6: areturn
This returns a boxed long. And then
public byte unwrap$mcB$sp();
Code:
0: aload_0
1: invokeinterface #16, 1; //InterfaceMethod unwrap:()Ljava/lang/Object;
6: invokestatic #36; //Method scala/runtime/BoxesRunTime.unboxToByte:(Ljava/lang/Object;)B
9: ireturn
And this unboxes the boxed long to a byte which does not work because BoxesRunTime.unboxToByte expects a java.lang.Byte, not a java.lang.Long.
This seems a compiler bug related to specializing, if I remove @specialized from
trait Unwrapper[@specialized(Byte) P] {
def unwrap: P = {
val result = 0L.asInstanceOf[P]
result
}
}
everything works fine. If my conclusions are correct, should I report this to scala-language or open a bug report for the Scala compiler?
Best regards,
Michael