These are some of the weird cases I encountered for suzaku-io/boopickle#21.
Full repo is here https://github.com/steinybot/bug-reports/tree/boopickle/diverging-implicits.
Something smells fishy...
These are some of the weird cases I encountered for suzaku-io/boopickle#21.
Full repo is here https://github.com/steinybot/bug-reports/tree/boopickle/diverging-implicits.
Something smells fishy...
package object pickle { | |
trait MyTypeA | |
// This has to have a type parameter. | |
trait MyTypeB[A] | |
import boopickle.Pickler | |
trait Implicits { | |
implicit lazy val myTypeAPickler: Pickler[MyTypeA] = ??? | |
} | |
case class MyFixedTuple(a: List[MyTypeA], b: List[MyTypeB[Any]]) | |
case class MyGenericTuple[A, B](a: A, b: B) | |
} |
package pickle | |
import boopickle.DefaultBasic._ | |
// This works. | |
object Good1 extends Implicits { | |
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle.DefaultBasic._ | |
// Same as Good1 but the implicit is on the object instead of the val. | |
// Fails with: | |
// [error] /src/main/scala/pickle/Bad1.scala:19:25: diverging implicit expansion for type boopickle.DefaultBasic.P[T1] | |
// [error] starting with lazy value myTypeAPickler in trait Implicits | |
// [error] state.unpickle[List[MyTypeB[Any]]] | |
// [error] ^ | |
object Bad1 extends Implicits { | |
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle.DefaultBasic._ | |
// Same as Good1 but we don't call the MyFixedTuple.apply method (WTF!?). | |
// Fails with: | |
//error] /src/main/scala/pickle/Bad2.scala:18:23: diverging implicit expansion for type boopickle.Pickler[List[pickle.MyTypeB[Any]]] | |
// [error] starting with lazy value myTypeBPickler in object Bad2 | |
// [error] state.unpickle[List[MyTypeB[Any]]] | |
// [error] ^ | |
object Bad2 extends Implicits { | |
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
state.unpickle[List[MyTypeA]] | |
state.unpickle[List[MyTypeB[Any]]] | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle.DefaultBasic._ | |
// Same as Good1 but we call the apply method of a tuple with type parameters (WTF!?). | |
// Fails with: | |
// [error] /src/main/scala/pickle/Bad3.scala:19:25: diverging implicit expansion for type boopickle.Pickler[List[pickle.MyTypeB[Any]]] | |
// [error] starting with lazy value myTypeBPickler in object Bad3 | |
// [error] state.unpickle[List[MyTypeB[Any]]] | |
// [error] ^ | |
object Bad3 extends Implicits { | |
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyGenericTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle._ | |
// Same as Bad1 but we extend BasicImplicitPicklers instead of importing DefaultBasic._ | |
// Fails with: | |
// [error] /src/main/scala/pickle/Bad4.scala:19:25: diverging implicit expansion for type pickle.Bad4.P[T] | |
// [error] starting with method iterablePickler in trait XCompatImplicitPicklers | |
// [error] state.unpickle[List[MyTypeB[Any]]] | |
// [error] ^ | |
object Bad4 extends Implicits with PicklerHelper with XCompatImplicitPicklers { | |
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle._ | |
import scala.collection.generic.CanBuildFrom | |
import scala.language.higherKinds | |
// Same as Bad1 but we define everything ourselves. | |
object Good2 extends Implicits { | |
implicit def iterablePickler[T: Pickler, V[_] <: Iterable[_]](implicit cbf: CanBuildFrom[Nothing, T, V[T]]): Pickler[V[T]] = | |
BasicPicklers.IterablePickler[T, V] | |
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle._ | |
import scala.collection.generic.CanBuildFrom | |
import scala.language.higherKinds | |
// Same as Good2 but with the additional mapPickler. | |
// Fails with: | |
// [error] /src/main/scala/pickle/Bad5.scala:29:25: diverging implicit expansion for type boopickle.Pickler[T] | |
// [error] starting with method iterablePickler in object Bad5 | |
// [error] state.unpickle[List[MyTypeB[Any]]] | |
// [error] ^ | |
object Bad5 extends Implicits { | |
implicit def mapPickler[T: Pickler, S: Pickler, V[_, _] <: scala.collection.Map[_, _]]( | |
implicit cbf: CanBuildFrom[Nothing, (T, S), V[T, S]]): Pickler[V[T, S]] = | |
BasicPicklers.MapPickler[T, S, V] | |
implicit def iterablePickler[T: Pickler, V[_] <: Iterable[_]](implicit cbf: CanBuildFrom[Nothing, T, V[T]]): Pickler[V[T]] = | |
BasicPicklers.IterablePickler[T, V] | |
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
// Same as Good1 but with the import moved into the object. | |
// Fails with: | |
// [error] /src/main/scala/pickle/Bad6.scala:19:25: diverging implicit expansion for type boopickle.DefaultBasic.P[T1] | |
// [error] starting with lazy value myTypeAPickler in trait Implicits | |
// [error] state.unpickle[List[MyTypeB[Any]]] | |
// [error] ^ | |
object Bad6 extends Implicits { | |
import boopickle.DefaultBasic._ | |
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle.DefaultBasic.{mapPickler => _, _} | |
// Same as Bad1 but we hide the mapPickler. | |
object Good3 extends Implicits { | |
// implicit def listPickler[A: Pickler]: Pickler[List[A]] = boopickle.DefaultBasic.iterablePickler[A, List] | |
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle._ | |
import scala.collection.generic.CanBuildFrom | |
import scala.language.higherKinds | |
// Same as Bad5 but without the higher-kinded type for the mapPickler. | |
object Good4 extends Implicits { | |
implicit def mapPickler[T: Pickler, S: Pickler]( | |
implicit cbf: CanBuildFrom[Nothing, (T, S), Map[T, S]]): Pickler[Map[T, S]] = | |
BasicPicklers.MapPickler[T, S, Map] | |
implicit def iterablePickler[T: Pickler, V[_] <: Iterable[_]](implicit cbf: CanBuildFrom[Nothing, T, V[T]]): Pickler[V[T]] = | |
BasicPicklers.IterablePickler[T, V] | |
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = { | |
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] { | |
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = { | |
MyFixedTuple( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeB[Any]]] | |
) | |
??? | |
} | |
} | |
MyTypeBPickler | |
} | |
} |
package pickle | |
import boopickle.DefaultBasic._ | |
// Same as Bad1 but no nested higher-kinded types. | |
object Good5 extends Implicits { | |
lazy val myTypeCPickler: Pickler[MyTypeC] = { | |
implicit object MyTypeCPickler extends Pickler[MyTypeC] { | |
override def pickle(v: MyTypeC)(implicit state: PickleState): Unit = ??? | |
override def unpickle(implicit state: UnpickleState): MyTypeC = { | |
MyFixedTuple2( | |
state.unpickle[List[MyTypeA]], | |
state.unpickle[List[MyTypeC]] | |
) | |
??? | |
} | |
} | |
MyTypeCPickler | |
} | |
} |