Search code examples
scalaserializationpickler

java.lang.VerifyError: Bad type on operand stack using Scala Pickle


The following code:

import scala.pickling.{FastTypeTag, Pickler, Unpickler}
import scala.pickling.binary._
import scala.pickling.Defaults._

class Serializer[T : Pickler : FastTypeTag] {
  def serialize(data: T): Array[Byte] = {
    Foo.bar(data)
  }
}

object Foo {
  def bar[T: Pickler: FastTypeTag](t: T): Array[Byte] = t.pickle.value
  def unbar[T: Unpickler: FastTypeTag](bytes: Array[Byte]): T = bytes.unpickle[T]
}

class Message(message: String)

implicit object messageSerializer extends Serializer[Message]

def test[A: Pickler: FastTypeTag: Serializer](message: A): Array[Byte] = {
  implicitly[Serializer[A]].serialize(message)
}

val message = new Message("message")

test(message)

Evaluates to:

import scala.pickling.{FastTypeTag, Pickler, Unpickler}
import scala.pickling.binary._
import scala.pickling.Defaults._

defined class Serializer





defined module Foo




defined class Message

defined module messageSerializer

test: test[A](val message: A)(implicit <synthetic> val evidence$10: scala.pickling.Pickler[A],implicit <synthetic> val evidence$11: pickling.FastTypeTag[A],implicit <synthetic> val evidence$12: Serializer[A]) => Array[Byte]



message: Message = com.impresign.hub.core.A$A12$A$A12$Message@6c7df044

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    com/impresign/hub/core/A$A12$A$A12$messageSerializer$.<init>(Lcom/impresign/hub/core/A$A12$A$A12;)V @212: invokespecial
  Reason:
    Type uninitializedThis (current frame, stack[3]) is not assignable to 'com/impresign/hub/core/A$A12$A$A12$messageSerializer$'
  Current Frame:
    bci: @212
    flags: { flagThisUninit }
    locals: { uninitializedThis, 'com/impresign/hub/core/A$A12$A$A12', 'scala/runtime/VolatileObjectRef', 'scala/Tuple2' }
    stack: { uninitializedThis, 'com/impresign/hub/core/A$A12$A$A12', 'scala/Predef$', uninitializedThis, 'scala/runtime/VolatileObjectRef', 'com/impresign/hub/core/A$A12$A$A12' }
  Bytecode:
    0x0000000: 2a2b b200 2db8 0031 4db2 0036 b600 3ab9
    0x0000010: 0040 0100 b900 4601 0099 00c5 bb00 4859
    0x0000020: b200 36b6 003a b900 4001 00b2 004d 124f
    0x0000030: b200 54b6 0058 b900 5e01 00b9 0062 0200
    0x0000040: b200 36b6 003a b900 4001 00b2 004d 124f
    0x0000050: b200 54b6 0058 b900 5e01 00b9 0065 0200
    0x0000060: b700 684e 2dc6 006c 2db6 006c c000 6e3a
    0x0000070: 042d b600 71c0 006e 3a05 1904 c100 7399
    0x0000080: 0052 1904 c000 733a 0619 06b6 0076 c000
    0x0000090: 783a 0719 05c1 0073 9900 3919 05c0 0073
    0x00000a0: 3a08 1908 b600 76c0 007a 3a09 1907 1909
    0x00000b0: 3a0a 59c7 000c 5719 0ac6 000e a700 1519
    0x00000c0: 0ab6 0080 9900 0d19 07c0 0082 3a0b a700
    0x00000d0: 0b2a 2c2b b700 843a 0b19 0ba7 0009 2a2c
    0x00000e0: 2bb7 0084 b600 88c0 0078 b200 4d12 4fb2
    0x00000f0: 0054 b600 58b7 008b b1                 
  Stackmap Table:
    full_frame(@191,{UninitializedThis,Object[#147],Object[#10],Object[#72],Object[#110],Object[#110],Object[#115],Object[#120],Object[#115],Object[#122],Object[#122]},{UninitializedThis,Object[#147],Object[#41],Object[#120]})
    full_frame(@199,{UninitializedThis,Object[#147],Object[#10],Object[#72],Object[#110],Object[#110],Object[#115],Object[#120],Object[#115],Object[#122],Object[#122]},{UninitializedThis,Object[#147],Object[#41]})
    full_frame(@209,{UninitializedThis,Object[#147],Object[#10],Object[#72]},{UninitializedThis,Object[#147],Object[#41]})
    full_frame(@217,{UninitializedThis,Object[#147],Object[#10],Object[#72],Top,Top,Top,Top,Top,Top,Top,Object[#130]},{UninitializedThis,Object[#147],Object[#41]})
    full_frame(@222,{UninitializedThis,Object[#147],Object[#10]},{UninitializedThis,Object[#147],Object[#41]})
    full_frame(@228,{UninitializedThis,Object[#147],Object[#10]},{UninitializedThis,Object[#147],Object[#41],Object[#130]})
Output exceeds cutoff limit.

Never saw anything like it. I'd like to use implicit Serializers with Scala Pickler 0.10 under the hood. Is this achievable? Scala 2.11.8.


Solution

  • If you change your implicit object declaration to a val

    implicit val mssgSerializer: Serializer[Message] = new Serializer[Message]
    

    everything works nicely. As @laughedelic comment mentions, this is probably due to some funny interaction between macros and objects initialization.

    Tested with Scala 2.11.8 and Scala Pickling 0.10.1.